简体   繁体   中英

Does golang atomic.Load have a acquire semantics?

Given a c++ code snip:

int a = 0;
atomic<int> b{0};

Thread 1                         
a = 1;
b.store(1,memory_order_release);

Thread 2
while(!b.load(memory_order_acquire)); 
assert(a==1);

We know the assert never fire.

At the other hand, golang atomic.Store uses xchg instruction which implicts memory-barrier, so it can result in memory_order_release semantics as c++11.

//go:noescape
func Store(ptr *uint32, val uint32)
TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12
    MOVQ    ptr+0(FP), BX
    MOVL    val+8(FP), AX
    XCHGL   AX, 0(BX)
    RET

However, the implementation of atomic.Load is pure go code, which means just mov instruction when assembly.

//go:nosplit
//go:noinline
func Load(ptr *uint32) uint32 {
    return *ptr
}

So, does golang atomic.Load have a acquire semantics?
If do how it works, and if not how to insure memory-ordering or make a=1 visible?

On strongly ordered architectures like x86/amd64, acquire load and release store are just regular loads and stores. To make them atomic you need to ensure the memory is aligned to the operand size (automatic in Go), and that the compiler doesn't re-order them in incompatible ways, or optimize them away (eg reuse a value in a register instead of reading it from memory.)

The Go atomic Load* and Store* functions are sequentially consistent. This is a stronger form of memory ordering that requires memory fences (or instructions that have an implicit memory fence) even on x86/amd64.

Quoting rsc:

Go's atomics guarantee sequential consistency among the atomic variables (behave like C/C++'s seqconst atomics), and that you shouldn't mix atomic and non-atomic accesses for a given memory word.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM