Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a memory_order_seq_cst fence useful?

C++ supported atomic thread fences, that is fences guaranteeing properties for thread that use std::atomic<> operations, with the function atomic_thread_fence. It takes a memory order parameter to adjust the "strength" of the fence.

I understand that fences are useful when not all atomic operations are done with a "strong" order:

  • when not all atomic reads (1) in a thread are acquire operations, you may find a use for an acquire fence;
  • when not all atomic modifications (1) in a thread are release operations, you may find a use for a release fence.

(1) that includes RMW operations

So the usefulness of all these (acquire, release and acq_rel fences) is obvious: they allow threads that use atomic operations weaker than acq/rel (respectively) to synchronize properly.

But I don't understand where memory_order_seq_cst could be specifically needed as a fence:

  • What's the implication of using weaker than memory_order_seq_cst atomic operations and a memory_order_seq_cst fence?

  • What would specifically be guaranteed (in term of possible ordering of atomic operations) by a memory_order_seq_cst fence that wouldn't be guaranteed by memory_order_acq_rel?

like image 567
curiousguy Avatar asked Dec 13 '19 04:12

curiousguy


People also ask

What is Memory_order_seq_cst?

The default is std::memory_order_seq_cst which establishes a single total ordering over all atomic operations tagged with this tag: all threads see the same order of such atomic operations and no memory_order_seq_cst atomic operations can be reordered.

What is Memory_order_acquire?

memory_order_acquire. A load operation with this memory order performs the acquire operation on the affected memory location: no reads or writes in the current thread can be reordered before this load.


1 Answers

No, a seq-cst-fence is not only both a release and an acquire-fence, but also provides some additional properties (see Working Draft, Standard for Programming Language C++, 32.4.4-32.4.8). A seq-cst fence is also part of the single total order of all sequentially consistent operations, enforcing the following observations:

  • For an atomic operation B that reads the value of an atomic object M, if there is a memory_order_seq_cst fence X sequenced before B, then B observes either the last memory_order_seq_cst modification of M preceding X in the total order S or a later modification of M in its modification order.
  • For atomic operations A and B on an atomic object M, where A modifies M and B takes its value, if there is a memory_order_seq_cst fence X such that A is sequenced before X and B follows X in S, then B observes either the effects of A or a later modification of M in its modification order.
  • For atomic operations A and B on an atomic object M, where A modifies M and B takes its value, if there are memory_order_seq_cst fences X and Y such that A is sequenced before X, Y is sequenced before B, and X precedes Y in S, then B observes either the effects of A or a later modification of M in its modification order.

For example, I am using seq-cst fences in my hazard pointer implementation: https://github.com/mpoeter/xenium/blob/master/xenium/reclamation/impl/hazard_pointer.hpp
The thread acquiring a safe reference to some object uses seq-cst fence after storing the hazard pointer, but before re-reading the pointer to the object. The thread trying to reclaim some objects uses a seq-cst fence before gathering the active hazard pointers from all threads. Based on the rules above this ensures that either the thread trying to reclaim the object sees that some other thread has a HP for this object (i.e., the object is used), or the reload of thread trying to acquire the safe reference to the object returns a different pointer, indicating to that thread that the object has been removed and it has to perform a retry.

like image 147
mpoeter Avatar answered Oct 22 '22 02:10

mpoeter