2 回答
TA贡献1830条经验 获得超9个赞
这是竞争条件的经典例子。value++
不是原子操作,因此无法保证在没有同步的情况下从多个线程调用时它会正确或确定地工作。
给出一些直觉,value++
或多或少等同于value = value + 1
. 您可以将其视为三个操作,而不是一个:value
从内存加载到 CPU 寄存器,增加寄存器中的值(您不能直接修改内存),将值存储回内存。两个线程可能同时加载相同的值,增加它,得到相同的结果,然后将它写回,所以它实际上增加了value
1,而不是两个。
由于线程之间的操作顺序是不确定的,因此结果也是不确定的。
同样的效果发生在totalOps
. 但是,totalIncOps
和totalDecOps
只能由单个线程修改/读取,因此这里没有竞争,它们的最终值是确定性的。
TA贡献1818条经验 获得超8个赞
因为对变量 value、totalOps、totalIncOps 和 totalDecOps 的操作没有被锁定
添加互斥锁应该有所帮助。Go race detector 功能会发现这个错误
var m sync.Mutex
func increaseByOne(N int, waitGroup *sync.WaitGroup) {
for i := 0; i < N; i++ {
m.Lock()
value++
// Collecting stats
totalOps++
totalIncOps++
m.Unlock()
}
waitGroup.Done()
}
// Same with decrease
func decreaseByOne(N int, waitGroup *sync.WaitGroup) {
for i := 0; i < N; i++ {
m.Lock()
value--
// Collecting stats
totalOps++
totalDecOps++
m.Unlock()
}
waitGroup.Done()
}
上述方法的替代方法是对计数器使用 Sync.Atomic
- 2 回答
- 0 关注
- 107 浏览
添加回答
举报