6

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?

api
  • 305
  • 2
  • 8
  • 2
    There's an extensive discussion in this issue: https://github.com/golang/go/issues/5045 – Eli Bendersky Apr 22 '19 at 12:23
  • I just read it hard and find that they are seems to discuss more "try to design a concrete model against 95% scene" than "give many models and let user choose" like c++11. However, the discussion seems useless to my problem. – api Apr 23 '19 at 06:50

1 Answers1

3

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 (e.g. 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.

Eloff
  • 20,828
  • 17
  • 83
  • 112
  • Thanks, at least i won't worry about x86/amd64 for its strongly ordered architecture. At the other hand, if atomic.Load* and atomic.Store* are seqconst in golang, there should have fence instructions relevant to gurantee it. But i can't find any fence there. – api Dec 08 '19 at 17:51
  • If you look in `src/runtime/internal/atomic/asm_amd64.s` you'll find the store instructions use an implicit fence with the XCHG instruction. So I stand by the sequential consistency claim. – Eloff Jan 07 '20 at 15:06
  • I can understand xchg instruction on x86/amd64 has a implicit sfence, and mov has acquire semantic or lfence on strongly ordered architecture like x86/amd64. what makes me confused is lfence&&sfence == sequential-consistency or lfence||sfence==sequential-consistency, which statement is right. I choose the former, so i evolve that golang should give explicit full-fence instruction instead of implicit half-fence to gurantee sequential consistency. – api Feb 06 '20 at 05:22
  • I've wondered about that myself, but I don't know for sure. Please open a ticket on the Go issue tracker about it. – Eloff Feb 07 '20 at 18:02
  • @api LFENCE and SFENCE combined do not provide sequential consistency. One good reason is that non of them will wait for the store buffer to be drained and this can lead to an older store being reordered with a newer load to a different address. So they do not provide a [StoreLoad]. For this you need a MFENCE (or locked instruction like xchg). SFENCE AFAIK is only useful for weakly ordered stores like from SSE since regular store can't be reordered on X86 (all stores will commit in order to the coherent cache). – pveentjer Aug 30 '22 at 08:18
  • @api X86 is a strongly ordered architecture since only an older store can be reordered with a newer load to a different address due to store buffers. But the ARM is not a strongly ordered architecture since loads/stores to different addresses can be reordered. – pveentjer Aug 30 '22 at 08:21