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

时间:2017-02-14 16:21:07

标签: memory go concurrency atomic

我知道可以发生g打印2然后给出以下代码的情况。

var a, b uint32

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

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

func main() {
    go f()
    g()
}

如果我将所有读写更改为原子操作怎么办?是否保证如果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()
}

2 个答案:

答案 0 :(得分:2)

没有。没有同步,因此没有"happens before"关系。

goroutines之间的

Synchronization是通过通道通信和锁定操作完成的。

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

  

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

答案 1 :(得分:2)

实际上它会像你描述的那样工作。 Go编译器不会重新排序原子操作,并且使用amd64上的XCHG(以及其他体系结构上的类似指令)实现原子存储:https://github.com/golang/go/blob/release-branch.go1.8/src/cmd/compile/internal/ssa/gen/AMD64.rules#L472

目前尚未指定此行为(从Go 1.8开始)并且可能会发生变化,请参阅https://github.com/golang/go/issues/5045上的讨论以获取更多见解。