c++multithreadinglanguage-lawyeratomicmemory-barriers

What does memory_order::acquire do for a read-modify-write operation?


Another developer has shown me the following snippet:

std::atomic_flag lock;
// ...
while (lock.test_and_set(std::memory_order::acquire)) {}
// critical section
lock.clear(std::memory_order::release);

I'm confused about what specifying acquire as the memory order does here. Is this implicitly the same order as acq_rel, or is it acquire for the load operation and seq_cst (the default) for the store operation within this read-modify-write operation?

std::atomic_flag::test_and_set has no preconditions and it is merely said that:

Memory is affected according to the value of order.

That doesn't clarify things for me. What if order is acquire? How is the store affected then, huh?


Solution

  • Memory orders are (only) described in terms of their effect on synchronization and sequencing.

    An atomic operation A that performs a release operation on an atomic object M synchronizes with an atomic operation B that performs an acquire operation on M and takes its value from any side effect in the release sequence headed by A.

    The effect of the acquire on the "test" part of test_and_set is obvious. As for its effect on the "set" part? Well, it doesn't have one. As with relaxed, there's simply no useful guarantees the standard provides. So it's equivalent to something like memory_order::acq_relaxed. The compiler is free to move read/writes downward past the test_and_set, but not to move them upward.