我正在尝试重现一个问题,并使用以下代码找到了最小用例。如果我关闭所有通道(绕过 i == 0 测试),一切都会按预期进行。Wg 状态递减并触发完成,主要退出正常。当我跳过关闭这些通道之一(故意)时,我希望主例程等待,而在这种情况下等待组信号量将无限期阻塞。相反,我收到了一个错误:“致命错误:所有 goroutine 都睡着了 - 死锁!”。这是为什么?我一定错过了一些基本的东西,还是运行时过于热心了?
package main
import (
"fmt"
"sync"
)
const N int = 4
func 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{}{}一样。在这种情况下编译器也会抱怨吗?
小怪兽爱吃肉
守着一只汪
相关分类