在本文中,我们将分析“死锁”背后的原因!由以下代码片段中涉及 Go 通道的死锁情况引起的错误:
package main import ( "fmt" "sync" ) func push(c chan int, wg sync.WaitGroup) { for i := 0; i < 5; i++ { c <- i } wg.Done() } func pull(c chan int, wg sync.WaitGroup) { for i := 0; i < 5; i++ { result, ok := <-c fmt.Println(result, ok) } wg.Done() } func main() { var wg sync.WaitGroup wg.Add(2) c := make(chan int) go push(c, wg) go pull(c, wg) wg.Wait() }
运行此代码时,我们遇到以下错误:
throw: all goroutines are asleep - deadlock!
发生死锁是因为结构(例如此代码中的sync.WaitGroup)是按值传递而不是按引用传递。这意味着当我们将 WaitGroup 传递给我们的函数(推和拉)时,我们实际上传递的是 WaitGroup 的副本而不是原始对象。
因此,每个函数都在其自己的副本上工作WaitGroup 的副本,当它们调用 wg.Done() 时,它们会递减自己的副本。这不会更新我们的主协程正在等待的原始 WaitGroup,从而导致死锁。
要解决这个问题,我们需要传递指针到 WaitGroup 而不是值。这将确保推送和拉取函数都在 WaitGroup 的同一个实例上工作,并且它们对 wg.Done() 的调用将影响原始对象。
这是代码的更正版本:
package main import ( "fmt" "sync" ) func push(c chan int, wg *sync.WaitGroup) { for i := 0; i < 5; i++ { c <- i } wg.Done() } func pull(c chan int, wg *sync.WaitGroup) { for i := 0; i < 5; i++ { result, ok := <-c fmt.Println(result, ok) } wg.Done() } func main() { var wg sync.WaitGroup wg.Add(2) c := make(chan int) go push(c, &wg) go pull(c, &wg) wg.Wait() }
通过进行此更改,我们现在将指向 WaitGroup 的指针传递给我们的函数,确保它们都在同一对象上工作并正确更新其状态。这消除了死锁情况,让我们的程序能够无错误地运行。
以上是使用sync.WaitGroup时如何修复Go通道中的死锁错误?的详细内容。更多信息请关注PHP中文网其他相关文章!