Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 memory orderings- the differences?

I am currently reading Concurrency in Action and on page 111 it gives this sample code relating to a std::atomic_flag in order to explain how memory orderings work:

f.clear(std::memory_order_release);
bool x = f.test_and_set();

but all it says is:

Here, the call to clear()explicitly requests that the flag is cleared with release semantics, while the call to test_and_set() uses the default memory ordering for setting the flag and retrieving the old value.

They haven't actually explained what the differences are. Could somebody provide a general overview of how these memory orderings work? So not just the one I have mentioned above, but I believe there are a few more:

memory_order_relaxed
memory_order_release
memory_order_seq_cst
memory_order_consume
memory_order_acquire
memory_order_acq_rel
like image 375
user997112 Avatar asked Nov 10 '22 09:11

user997112


1 Answers

Informal characterisation (take it with a sack of salt):

  • SEQ_CST: the code behaves as if it was a simple interleaving of threads, with no reordering observable, as long as there are no data races.
  • RELEASE/ACQUIRE: A release "publishes" a write, and a read on that same memory location synchronizes with that write. As an example, a mutex lock may do an ACQUIRE, and a mutex unlock a RELEASE. Another example:

Example (atomic operations marked with their memory order on parenthesis):

t1:                                   t2:
   data = foo                            while not data_valid; (ACQUIRE)
   data_valid = true; (RELEASE)          bar = data;
  • ACQ_REL: does both an acquire and a release, for atomic RMW (Read-Modify-Write) operations. Note that you can specify to use ACQ_REL for a sucessful RMW, and another memory order if the RMW operation fails.
  • RELEASE/CONSUME: You publish a pointer to a structure, and a read "consumes" that publication, and can access the pointed-to data. Some Alpha processors had split caches, which meant that you could be reading a pointer from a bank of a cache, and the pointed-to data may not be still on other bank from that cache. In RCU as implemented on Linux, rcu_derefence() takes care of inserting a read barrier on Alpha between the read of the pointer and its dereference. Note that there has been some talk on totally changing the specification of the consume memory order (on a mailing list thread called "arch: atomic rework"), as it seems to be impractical for compiler writers. In particular, the current standard allows you to publish p, and *(q + (p-p)) is dependant on that. Some people contend that makes no sense at all.
  • RELAXED: Free for all.
like image 172
ninjalj Avatar answered Nov 15 '22 06:11

ninjalj