首页  >  文章  >  后端开发  >  为什么在 Go 中按值传递 WaitGroup 会导致死锁,如何解决?

为什么在 Go 中按值传递 WaitGroup 会导致死锁,如何解决?

Linda Hamilton
Linda Hamilton原创
2024-10-28 18:56:29520浏览

Why does passing a WaitGroup by value in Go lead to a deadlock, and how can it be resolved?

Go Channels 的死锁:变量作用域的问题

在 Golang 程序中,Channel 促进了 goroutine 之间的通信。然而,误用通道可能会导致死锁,如下面的代码所示:

<br>package main<p>import (</p><pre class="brush:php;toolbar:false">"fmt"
"sync"

)

func push(c chan int, wgsync.WaitGroup) {

for i := 0; i < 5; i++ {
    c <- i
}
wg.Done()

}

func pull(c chan int, wgsync.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() // Block the main thread until goroutines complete

}

运行此程序时,您可能会遇到出现以下错误:

fatal error: all goroutines are asleep - deadlock!

要理解为什么会发生这种死锁,让我们深入研究一下代码:

  • main 创建一个 WaitGroup、一个通道 c 以及用于推拉的 goroutine
  • push 和 pull 函数使用 WaitGroup 来同步它们的执行。
  • push 函数在循环中向 c 发送值,并通过调用 wg.Done() 来表示其完成。
  • pull 函数从 c 接收值并打印它们。它还使用 wg.Done() 发出完成信号。

问题在于如何将 WaitGroup 传递给 goroutine。当传递的值不带与号 (&) 时,它是按值传递,而不是按引用传递。在这种情况下,将为每个 goroutine 创建一个 WaitGroup 的副本。

因此,当每个 goroutine 调用 wg.Done() 时,它会修改其本地的 WaitGroup 副本。由于主线程会一直等待,直到 wg 指示所有 Goroutine 都已完成,因此它会无限期地等待,因为两个 Goroutine 都不会更新原始的 WaitGroup。这会导致死锁。

要解决此问题,我们需要通过引用传递 WaitGroup。这可以确保两个 goroutine 修改 WaitGroup 的同一实例,并向主线程正确发出完成信号。

这是经过更正的代码修订版:

<br>package main<p>import (</p><pre class="brush:php;toolbar:false">"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) // Pass the WaitGroup by reference using the ampersand
go pull(c, &wg) // Pass the WaitGroup by reference using the ampersand

wg.Wait()

}

通过引用传递WaitGroup,我们确保主线程能够正确判断两个goroutines何时完成任务,从而避免死锁。

以上是为什么在 Go 中按值传递 WaitGroup 会导致死锁,如何解决?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn