c++memory-barriersmemory-modelstdatomicrelaxed-atomics

What is the (slight) difference on the relaxing atomic rules?


After seeing Herb Sutters excellent talk about "atomic weapons" I got a bit confused about the Relaxed Atomics examples.

I took with me that an atomic in the C++ Memory Model (SC-DRF = Sequentially Consistent for Data Race Free) does an "acquire" on a load/read.

I understand that for a load [and a store] the default is std::memory_order_seq_cst and therefore the two are the same:

myatomic.load();                          // (1)
myatomic.load(std::memory_order_seq_cst); // (2)

So far so good, no Relaxed Atomics involved (and after hearing the talk I will never to use the relaxed ones. Ever. Promise. But when someone asks me, I might have to explain...).

But why is it the "relaxed" semantics when I use

myatomic.load(std::memory_order_acquire);   // (3)

Since load is acquiring and not releasing, why is this different from (1) and (2)? What actually is relaxed here?

The only thing I can think of is that I misunderstood that load means acquire. And if that is true, and the default seq_cst means both, doesn't that mean a full fence -- nothing can pass up that instruction, nor down? I have to have misunderstood that part.

[and symmetrically for store and release].


Solution

  • It can be a bit confusing to call myatomic.load(std::memory_order_acquire); a "relaxed atomic" load, since there is a std::memory_order_relaxed. Some people describe any order weaker than seq_cst as "relaxed".

    You're right to note that sequentially-consistent load is an acquire load, but it has an additional requirement: sequentially-consistent load is also a part of the total global order for all seq_cst operations.

    It comes into play when you're dealing with more than one atomic variable: individual modification orders of two atomics may appear in different relative order to different threads, unless sequential consistency is imposed.