为什么竞态检测器在这里报告竞态条件?
我正在使用 Go 竞争检测(-race 参数),它检测到一些我认为不应该报告的竞争条件问题。我创建了这个示例代码来解释我的发现。请不要对此示例的目标发表评论,因为它除了解释问题之外没有其他目标。
这段代码:
var count int
func main() {
go update()
for {
fmt.Println(count)
time.Sleep(time.Second)
}
}
func update() {
for {
time.Sleep(time.Second)
count++
}
}
报告有竞争条件。
虽然这段代码:
var count int
var mutex sync.RWMutex
func main() {
go update()
for {
mutex.RLock()
fmt.Println(count)
mutex.RUnlock()
time.Sleep(time.Second)
}
}
func update(){
for {
time.Sleep(time.Second)
mutex.Lock()
count++
mutex.Unlock()
}
}
没有报告任何竞争条件问题。
我的问题是为什么?第一个代码中没有错误。main 函数正在读取另一个 go 例程正在更新的变量。这里没有潜在的隐藏错误。第二个代码互斥锁不提供任何不同的行为。
我哪里错了?
回答
您的代码包含一个非常明确的种族。
您的 for 循环正在访问count另一个 goroutine 正在更新它的同时。这就是种族的定义。
main 函数正在读取另一个 go 例程正在更新的变量。
对,就是这样。赛跑就是这样。
第二个代码互斥锁不提供任何不同的行为。
是的,它确实。它防止变量从不同的 goroutines 同时被读取和写入。