29 Atomic operations library [atomics]

29.4 Order and consistency [atomics.order]

namespace std {
  enum class memory_order : unspecified {
    relaxed, consume, acquire, release, acq_rel, seq_cst
  };
  inline constexpr memory_order memory_order_relaxed = memory_order::relaxed;
  inline constexpr memory_order memory_order_consume = memory_order::consume;
  inline constexpr memory_order memory_order_acquire = memory_order::acquire;
  inline constexpr memory_order memory_order_release = memory_order::release;
  inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel;
  inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst;
}
The enumeration memory_­order specifies the detailed regular (non-atomic) memory synchronization order as defined in [intro.multithread] and may provide for operation ordering.
Its enumerated values and their meanings are as follows:
  • memory_­order​::​relaxed: no operation orders memory.
  • memory_­order​::​release, memory_­order​::​acq_­rel, and memory_­order​::​seq_­cst: a store operation performs a release operation on the affected memory location.
  • memory_­order​::​consume: a load operation performs a consume operation on the affected memory location.
    [ Note
    :
    Prefer memory_­order​::​acquire, which provides stronger guarantees than memory_­order​::​consume.
    Implementations have found it infeasible to provide performance better than that of memory_­order​::​acquire.
    Specification revisions are under consideration.
    — end note
     ]
  • memory_­order​::​acquire, memory_­order​::​acq_­rel, and memory_­order​::​seq_­cst: a load operation performs an acquire operation on the affected memory location.
[ Note
:
Atomic operations specifying memory_­order​::​relaxed are relaxed with respect to memory ordering.
Implementations must still guarantee that any given atomic access to a particular atomic object be indivisible with respect to all other atomic accesses to that object.
— end note
 ]
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.
There shall be a single total order S on all memory_­order​::​seq_­cst operations, consistent with the “happens before” order and modification orders for all affected locations, such that each memory_­order​::​seq_­cst operation B that loads a value from an atomic object M observes one of the following values:
  • the result of the last modification A of M that precedes B in S, if it exists, or
  • if A exists, the result of some modification of M that is not memory_­order​::​seq_­cst and that does not happen before A, or
  • if A does not exist, the result of some modification of M that is not memory_­order​::​seq_­cst.
[ Note
:
Although it is not explicitly required that S include locks, it can always be extended to an order that does include lock and unlock operations, since the ordering between those is already included in the “happens before” ordering.
— end note
 ]
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 atomic modifications A and B of an atomic object M, B occurs later than A in the modification order of M if:
  • there is a memory_­order​::​seq_­cst fence X such that A is sequenced before X, and X precedes B in S, or
  • there is a memory_­order​::​seq_­cst fence Y such that Y is sequenced before B, and A precedes Y in S, or
  • 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.
[ Note
:
memory_­order​::​seq_­cst ensures sequential consistency only for a program that is free of data races and uses exclusively memory_­order​::​seq_­cst operations.
Any use of weaker ordering will invalidate this guarantee unless extreme care is used.
In particular, memory_­order​::​seq_­cst fences ensure a total order only for the fences themselves.
Fences cannot, in general, be used to restore sequential consistency for atomic operations with weaker ordering specifications.
— end note
 ]
Implementations should ensure that no “out-of-thin-air” values are computed that circularly depend on their own computation.
[ Note
:
For example, with x and y initially zero,
// Thread 1:
r1 = y.load(memory_order::relaxed);
x.store(r1, memory_order::relaxed);
// Thread 2:
r2 = x.load(memory_order::relaxed);
y.store(r2, memory_order::relaxed);
should not produce r1 == r2 == 42, since the store of 42 to y is only possible if the store to x stores 42, which circularly depends on the store to y storing 42.
Note that without this restriction, such an execution is possible.
— end note
 ]
[ Note
:
The recommendation similarly disallows r1 == r2 == 42 in the following example, with x and y again initially zero:
// Thread 1:
r1 = x.load(memory_order::relaxed);
if (r1 == 42) y.store(42, memory_order::relaxed);
// Thread 2:
r2 = y.load(memory_order::relaxed);
if (r2 == 42) x.store(42, memory_order::relaxed);
— end note
 ]
Atomic read-modify-write operations shall always read the last value (in the modification order) written before the write associated with the read-modify-write operation.
Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.
template<class T> T kill_dependency(T y) noexcept;
Effects: The argument does not carry a dependency to the return value.
Returns: y.