【发布时间】:2021-09-02 20:28:06
【问题描述】:
我正在尝试理解 golang channels 和 synchronization。 当我使用race detector 运行我的程序时,它会导致竞争检测。
我的程序:
func main() {
ch := make(chan int)
done := make(chan struct{})
wg := sync.WaitGroup{}
go func() {
defer close(ch)
defer close(done)
wg.Wait()
done <- struct{}{}
}()
for i := 0; i < 5; i++ {
x := i
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("Value: ", x)
ch <- x
}()
}
loop:
for {
select {
case i := <-ch:
fmt.Println("Value: ", i)
case <- done:
break loop
}
}
}
种族检测报告:
==================
WARNING: DATA RACE
Write at 0x00c000020148 by goroutine 7:
internal/race.Write()
/home/linuxbrew/.linuxbrew/Cellar/go/1.16.5/libexec/src/internal/race/race.go:41 +0x125
sync.(*WaitGroup).Wait()
/home/linuxbrew/.linuxbrew/Cellar/go/1.16.5/libexec/src/sync/waitgroup.go:128 +0x126
main.main.func1()
/home/reddy/code/github.com/awesomeProject/prod.go:106 +0xc4
Previous read at 0x00c000020148 by main goroutine:
internal/race.Read()
/home/linuxbrew/.linuxbrew/Cellar/go/1.16.5/libexec/src/internal/race/race.go:37 +0x206
sync.(*WaitGroup).Add()
/home/linuxbrew/.linuxbrew/Cellar/go/1.16.5/libexec/src/sync/waitgroup.go:71 +0x219
main.main()
/home/reddy/code/github.com/awesomeProject/prod.go:112 +0x124
Goroutine 7 (running) created at:
main.main()
/home/reddy/code/github.com/awesomeProject/prod.go:103 +0x104
==================
我无法弄清楚这里出了什么问题。
我的分析:
-
wg.Add(1)正在递增计数器 -
wg.Done()在减少计数器的 goroutine 结束时调用 -
ch <- x这应该是一个阻塞调用,因为它是非缓冲通道 - 循环应该迭代直到完成通道有一些消息当
waitgroup计数器变为零时发生,即所有5个goroutine都发布了消息 - 一旦计数器归零,
wggoroutine 将恢复并调用 done,一旦消息在主循环中被消耗,它会中断循环并正常退出。
【问题讨论】:
-
第 112 行和第 106 行是什么?
-
@BurakSerdar wg.Add(1) -112 wg.Wait() -106
-
直接来自
sync's doc:请注意,当计数器为零时调用[对Add] 的正增量必须发生在Wait之前。具有负增量的调用或具有正增量的调用在计数器大于零时开始,可能随时发生。通常这意味着对Add的调用应该在创建 goroutine 的语句或其他要等待的事件之前执行。 -
您的第一个例程在等待组完成之前关闭
ch,因为您可能会在开始等待它的例程之后增加等待组。您也可以简单地关闭它,而不是进入完成的频道
标签: go channel goroutine waitgroup