去++运算符需要互斥吗?

时间:2019-01-29 09:22:47

标签: go

++运算符需要互斥吗? 看来,当不使用互斥锁时,我会丢失一些数据,但是通过逻辑++只能将+1值添加到当前值,所以即使顺序不正确,总共还是要运行1000次吗? 示例:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    i := 0
    for r := 0; r < 1000; r++ {
        wg.Add(1)
        go func() {
            i++
            fmt.Println(i)
            wg.Done()
        }()
    }
    wg.Wait()
    fmt.Printf("%d Done", i)
}

2 个答案:

答案 0 :(得分:2)

要“仅将1添加到当前值”,计算机需要读取当前值,将其添加1,然后 write 返回新值。显然订购很重要;标准示例是:

Thread A     Thread B
Read: 5
             Read: 5
+1 = 6
             +1 = 6
Write: 6
             Write: 6

该值从5开始,两个执行线程各加一个,结果为6(应为7),因为B的读取发生在A的写入之前。

但是这里有一个更重要的误解:很多人认为在比赛中,代码要么读取旧值,要么读取新值。 不能保证。这可能是大多数时间发生的情况。可能是在您的计算机上一直在发生,使用当前版本的编译器等。但是actually it's possible对于以不安全/不友好的方式访问数据以生成任何结果,甚至是完整的垃圾。如果引发种族,则无法保证您从变量中读取的值对应于曾经具有的任何值。

答案 1 :(得分:0)

  

只需将+1值添加到当前值

不,不是“只是添加”。是

  1. 读取当前值
  2. 计算新值(基于读取的值)并将其写入

看看如何与多个并发参与者一起打破?

如果要原子增量,请签出sync/atomic。示例:https://gobyexample.com/atomic-counters