[英]Race condition even when using sync.Mutex in golang
完整的代码在这里: https : //play.golang.org/p/ggUoxtcv5m go run -race main.go
说有一个竞争条件,我无法解释。 不过,该程序输出了正确的最终结果。
精华:
type SafeCounter struct {
c int
sync.Mutex
}
func (c *SafeCounter) Add() {
c.Lock()
c.c++
c.Unlock()
}
var counter *SafeCounter = &SafeCounter{} // global
在增量器中使用*SafeCounter
:
func incrementor(s string) {
for i := 0; i < 20; i++ {
x := counter
x.Add()
counter = x
}
}
incrementor
方法在main
生成两次:
func main() {
go incrementor()
go incrementor()
// some other non-really-related stuff like
// using waitGroup is ommited here for problem showcase
}
因此,正如我所说, go run -race main.go
将始终说有一个比赛cond发现。
此外,最终的结果总是正确的(至少我已经运行了多次这个程序,它总是说最终计数器是40,这是正确的)。 但是,程序在开头打印不正确的值,所以你可以得到类似的东西:
Incrementor1: 0 Counter: 2
Incrementor2: 0 Counter: 3
Incrementor2: 1 Counter: 4
// ang the rest is ok
所以,那里缺少打印1
。
有人可以解释为什么有竞争条件我的代码?
你有很多种族条件,所有比赛都由比赛探测器指出:
x := counter // this reads the counter value without a lock
fmt.Println(&x.c)
x.Add()
counter = x // this writes the counter value without a lock
time.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond)
fmt.Println(s, i, "Counter:", x.c) // this reads the c field without a lock
种族#1在incrementor
读取和写入counter
值之间
第2场比赛是在incrementor
对counter
值的并发写入之间
race#3介于fmt.Println
xc
字段的读取和Add
方法中xc
的增量之间。
读取和写入计数器指针的两行不受互斥锁保护,并且是从多个goroutine同时完成的。
func incrementor(s string) {
for i := 0; i < 20; i++ {
x := counter // <-- this pointer read
x.Add()
counter = x // <-- races with this pointer write
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.