32 Atomic operations library [atomics]

32.4 Order and consistency [atomics.order]

namespace std {
  enum memory_order {
    memory_order_relaxed, memory_order_consume, memory_order_acquire,
    memory_order_release, memory_order_acq_rel, 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.