为了账号安全,请及时绑定邮箱和手机立即绑定

得到一个致命错误:所有的 goroutine 都睡着了——死锁!有一个简单的测试场景

得到一个致命错误:所有的 goroutine 都睡着了——死锁!有一个简单的测试场景

Go
慕村9548890 2021-12-06 18:35:35
我正在尝试重现一个问题,并使用以下代码找到了最小用例。如果我关闭所有通道(绕过 i == 0 测试),一切都会按预期进行。Wg 状态递减并触发完成,主要退出正常。当我跳过关闭这些通道之一(故意)时,我希望主例程等待,而在这种情况下等待组信号量将无限期阻塞。相反,我收到了一个错误:“致命错误:所有 goroutine 都睡着了 - 死锁!”。这是为什么?我一定错过了一些基本的东西,还是运行时过于热心了?package mainimport (    "fmt"    "sync")const N int = 4func main() {    done := make(chan struct{})    defer close(done)    fmt.Println("Beginning...")    chans := make([]chan int, N)    var wg sync.WaitGroup    for i := 0; i < N; i++ {        wg.Add(1)        chans[i] = make(chan int)        go func(i int) { // p0            defer wg.Done()            for m := range chans[i] {                fmt.Println("Received ", m)            }            fmt.Println("Ending p", i)        }(i)    }    go func() {        wg.Wait()        done <- struct{}{} // signal main that we are done    }()    for i := 0; i < N; i++ {        fmt.Println("Closing c", i)        if i != 0 { // Skip #0 so wg doesn't reach '0'            close(chans[i])        }    }    <-done // wait to receive signal from anonymous join function    fmt.Println("Ending.")}更新:我编辑了代码以避免竞争条件。仍然收到此错误。if i != 0之所以存在,是因为它是故意的。我希望 wg.Wait 永远阻塞(其信号量永远不会达到 0。)为什么我不能这样做?这似乎与我在其他地方<-done没有匹配的情况下使用done <- struct{}{}一样。在这种情况下编译器也会抱怨吗?
查看完整描述

2 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

这是发生了什么:

  • 第一个go func(i int) {goroutine 没有退出,因为chans[0]没有关闭。

  • 因为 goroutine 没有退出,wg.Done也没有被调用。

  • wg.Wait()由于上一点,对永远阻塞的调用。

  • Main 永远阻塞,因为信号没有发送到done

您可以通过删除 来解决死锁if i != 0 {,但还有另一个问题。等待组有一场比赛。有可能在调用 wg.Add(1) 之前调用 wg.Done()。在启动 goroutine 之前调用 wg.Add() 以避免竞争。


查看完整回答
反对 回复 2021-12-06
?
守着一只汪

TA贡献1872条经验 获得超3个赞

if你的 for 循环中的语句不会让最后一个通道关闭,所以你goroutine要等待发生的事情,chans[i]这将阻止defer wg.Done()永远发生的事情,这反过来永远不会让wg.Wait()完成,THENNNNN 永远不会让done <- struct{}{}得到信号

简而言之,您if statement的循环并没有关闭最后一个通道并导致死锁,因为没有人无能为力。

正如@CodingPickle 确实指出的那样,将您移动wg.Add(1)到您的开头for loop以防止任何竞争条件

http://play.golang.org/p/j1D5LZGUhd


查看完整回答
反对 回复 2021-12-06
  • 2 回答
  • 0 关注
  • 178 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信