Golang指令重排与内存可见性探究

虽然Golang并没有像Java一样提供volatile关键字,但是在执行一些操作时还是会对指令进行重排或者说写操作不可见。下面举一个简单的例子来证明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func foo() {
    wg := sync.WaitGroup{}
    for {
        var a, b, c, d int64
        wg.Add(2)
        go func() {
            c = 1
            a = d
            wg.Done()
        }()
        go func() {
            d = 1
            b = c
            wg.Done()
        }()
        wg.Wait()
        if a == 0 && b == 0 {
            fmt.Println("a:", a, "b:", b)
        }
    }
}

如果按照顺序执行&协程中的变量可见,能print出a b的值应当是1 1、1 0、0 1,然而上面的程序却能打印出a: 0 b:0的结果。

上面的例子可能意义不大,但是证明了golang也存在指令重排&内存可见性的问题,既然golang没有volatile关键字,那么平时在书写代码时就需要遵循他的happens before原则。

作者

ZhongHuihong

发布于

2021-08-01

更新于

2021-10-02

许可协议