golang中的原子操作是否建立了先发生的关系?

luy*_*619 5 memory concurrency atomic go

我知道可以发生g打印2然后给出以下代码0.

var a, b uint32

func f() {
    a = 1
    b = 2
}

func g() {
    fmt.Println(b)
    fmt.Println(a)
}

func main() {
    go f()
    g()
}
Run Code Online (Sandbox Code Playgroud)

如果我将所有读写更改为原子操作怎么办?是否保证如果g先打印2,那么还会打印1?

var a, b uint32

func f() {
    atomic.StoreUint32(&a, 1)
    atomic.StoreUint32(&b, 2)
}

func g() {
    fmt.Println(atomic.LoadUint32(&b))
    fmt.Println(atomic.LoadUint32(&a))
}

func main() {
    go f()
    g()
}
Run Code Online (Sandbox Code Playgroud)

Jim*_*imB 2

不会。没有同步,因此不存在“发生在之前”的关系。

Goroutine 之间的同步是通过通道通信和锁定操作来完成的。

内存模型中的一个关键段落是:

在单个 goroutine 中,读取和写入的行为必须就像按照程序指定的顺序执行一样。也就是说,只有当重新排序不会改变语言规范定义的 Goroutine 内的行为时,编译器和处理器才可以对单个 Goroutine 内执行的读取和写入进行重新排序。由于这种重新排序,一个 Goroutine 观察到的执行顺序可能与另一个 Goroutine 观察到的顺序不同。例如,如果一个 goroutine 执行 a = 1; b = 2;,另一个人可能会在 a 的更新值之前观察到 b 的更新值。

  • @Tinwor:不,这不能保证,特别是没有原子操作。每个 goroutine 可能位于不同的线程中、不同的核心上、不同的 NUMA 节点上并查看不同的内存。即使使用原子操作,操作的隐式顺序从技术上讲也只适用于 goroutine 内,所以我认为内存模型不能保证它。 (2认同)