【发布时间】:2018-05-22 16:56:45
【问题描述】:
以下 Go 代码示例在行 c <- byte(0) 和 close(c) 之间有一个竞态条件。使用go test -race 运行代码时会发出信号。
func TestRace(t *testing.T) {
var c = make(chan byte, 20)
go func() {
defer func() {
if r := recover(); r == nil {
t.Error("expected panic error")
}
}()
for i := 0; i < 25; i++ {
c <- byte(0)
}
t.Error("expected a panic")
}()
close(c)
}
如何避免这种竞争状况?
编辑:根据 Icza 在他的 cmets 中的建议,解决方案如下:
func TestRace(t *testing.T) {
var c = make(chan byte, 20)
var done = make(chan struct{})
go func() {
for i := 0; i < 25; i++ {
select{
case c <- byte(0):
case <-done:
close(c)
return
}
}()
close(done)
}
这不会有竞争条件,并且是干净的。这是一个愚蠢的简单例子。有人告诉我选择会增加开销,但我没有调查它,因为它与我的用例无关。
【问题讨论】:
-
向上移动
close(c)以便它在 goroutine 移除竞争条件之前执行。如果出于某种原因,关闭通道和写入通道的责任必须属于不同的 goroutine,那么竞争条件可能总是存在。不过,WaitGroups 和其他锁可能会提供一种安全的方法。
标签: go concurrency race-condition channel goroutine