Doc. No.: | N1349 | ||
---|---|---|---|
Date: | 2009-02-23 | ||
Reply to: | Clark Nelson | Hans-J. Boehm | Lawrence Crowl |
Phone: | +1-503-712-8433 | +1-650-857-3406 | +1-650-253-3677 |
Email: | clark.nelson@intel.com | Hans.Boehm@hp.com boehm@acm.org |
crowl@google.com Lawrence@Crowl.org |
This paper proposes changes to the WD for the next revision of the C standard to incorporate the C++ parallel memory sequencing model.
For rationale and explanation of the memory model overall, see N1276. For additional rationale and explanation of the design of the atomic (library) facilities, see N1284, the predecessor of this paper.
Changes since N1284 include:
Most of the atomic operations specified herein are type-generic. The style of
the specifications herein is similar to that of the <math.h>
classification
and comparison macros. All these specifications, plus those in <tgmath.h>
,
are expected to be cleaned up by a proposal for general-purpose type-generic macro
facilities.
WG21 has also adopted modifications to the memory model for memory dependence ordering. That is not incorporated in this proposal; it is expected to be the subject of a later proposal.
Add a new subclause to clause 3:
- memory location
- either an object of scalar type, or a maximal sequence of adjacent bit-fields all having non-zero width
NOTE 1 Two threads of execution can update and access separate memory locations without interfering with each other.
NOTE 2 A bit-field and an adjacent non-bit-field member are in separate memory locations. The same applies to two bit-fields, if one is declared inside a nested struct declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field member declaration. It is not safe to concurrently update two bit-fields in the same struct if all members declared between them are also bit-fields, no matter what the sizes of those intervening bit-fields happen to be.
EXAMPLE A structure declared as
struct { char a; int b:5, c:11, :0, d:8; struct { int ee:8; } e; }contains four separate memory locations: The member
a
, and bit-fieldsd
ande.ee
are each separate memory locations, and can be modified concurrently without interfering with each other. The bit-fieldsb
andc
together constitute the fourth memory location. The bit-fieldsb
andc
cannot be concurrently modified, butb
anda
, for example, can be.
Insert a new subclause after 5.1.2.3, with the following paragraphs.
5.1.2.4p1:
Under a hosted implementation, a C program can have more than one thread of execution (a.k.a. thread) running concurrently. The execution of each thread proceeds as defined by the remainder of this standard. The execution of the entire program consists of an execution of all of its threads. « Footnote: Usually the execution can be viewed as an interleaving of all its threads. However some kinds of atomic operations, for example, allow executions inconsistent with a simple interleaving, as described below. » Under a freestanding implementation, it is implementation-defined whether a program can have more than one thread of execution.
5.1.2.4p2:
The value of an object visible to a thread T at a particular point might be the initial value of the object, a value assigned to the object by T, or a value assigned to the object by another thread, according to the rules below.
5.1.2.4p3:
NOTE In some cases, there may instead be undefined behavior. Much of this section is motivated by the desire to support atomic operations with explicit and detailed visibility constraints. However, it also implicitly supports a simpler view for more restricted programs.
5.1.2.4p4:
Two expression evaluations conflict if one of them modifies a memory location and the other one accesses or modifies the same memory location.
5.1.2.4p5:
The library defines a number of atomic operations («ATM») and operations on locks (???) that are specially identified as synchronization operations. These operations play a special role in making assignments in one thread visible to another. A synchronization operation on one or more memory locations is either an acquire operation or a release operation, or both an acquire and release operation. A synchronization operation without an associated memory location is a fence and can be either an acquire fence, a release fence, or both an acquire and release fence. In addition, there are relaxed atomic operations, which are not synchronization operations, and atomic read-modify-write operations, which have special characteristics.
5.1.2.4p6:
NOTE For example, a call that acquires a lock will perform an acquire operation on the locations comprising the lock. Correspondingly, a call that releases the same lock will perform a release operation on those same locations. Informally, performing a release operation on A forces prior side effects on other memory locations to become visible to other threads that later perform an acquire operation on A. We do not include relaxed atomic operations as synchronization operations although, like synchronization operations, they cannot contribute to data races.
5.1.2.4p7:
All modifications to a particular atomic object M occur in some particular total order, called the modification order of M. If A and B are modifications of an atomic object M, and A happens before B, then A shall precede B in the modification order of M, which is defined below.
5.1.2.4p8:
NOTE 1 This states that the modification orders must respect the "happens before" relation.
5.1.2.4p9:
NOTE 2 There is a separate order for each atomic object. There is no requirement that these can be combined into a single total order for all objects. In general this will be impossible since different threads may observe modifications to different variables in inconsistent orders.
5.1.2.4p10:
A release sequence on an atomic object M is a maximal contiguous sub-sequence of side effects in the modification order of M, where the first operation is a release, and every subsequent operation
- is performed by the same thread that performed the release, or
- is an atomic read-modify-write operation.
5.1.2.4p11:
Certain library calls synchronize with other library calls performed by another thread. In particular, an atomic operation A that performs a release operation on an object M synchronizes with an atomic operation B that performs an acquire operation on M and reads a value written by any side effect in the release sequence headed by A.
5.1.2.4p12:
NOTE 1 Except in the specified cases, reading a later value does not necessarily ensure visibility as described below. Such a requirement would sometimes interfere with efficient implementation.
5.1.2.4p13:
NOTE 2 The specifications of the synchronization operations define when one reads the value written by another. For atomic variables, the definition is clear. All operations on a given lock occur in a single total order. Each lock acquisition "reads the value written" by the last lock release.
5.1.2.4p14:
An evaluation A inter-thread happens before an evaluation B if
- A synchronizes with B, or
- for some evaluation X
- A synchronizes with X and X is sequenced before B, or
- A is sequenced before X and X inter-thread happens before B, or
- A inter-thread happens before X and X inter-thread happens before B.
5.1.2.4p15:
An evaluation A happens before an evaluation B if:
- A is sequenced before B, or
- A inter-thread happens before B.
5.1.2.4p16:
A visible side effect A on an object M with respect to a value computation B of M satisfies the conditions:
- A happens before B, and
- there is no other side effect X to M such that A happens before X and X happens before B.
The value of a non-atomic scalar object M, as determined by evaluation B, shall be the value stored by the visible side effect A.
5.1.2.4p17:
NOTE 1 If there is ambiguity about which side effect to a non-atomic object is visible, then there is a data race, and the behavior is undefined.
5.1.2.4p18:
NOTE 2 This states that operations on ordinary variables are not visibly reordered. This is not actually detectable without data races, but it is necessary to ensure that data races, as defined here, and with suitable restrictions on the use of atomics, correspond to data races in a simple interleaved (sequentially consistent) execution.
5.1.2.4p19:
The visible sequence of side effects on an atomic object M, with respect to a value computation B of M, is a maximal contiguous sub-sequence of side effects in the modification order of M, where the first side effect is visible with respect to B, and for every subsequent side effect, it is not the case that B happens before it. The value of an atomic object M, as determined by evaluation B, shall be the value stored by some operation in the visible sequence of M with respect to B. Furthermore, if a value computation A of an atomic object M happens before a value computation B of M, and the value computed by A corresponds to the value stored by side effect X, then the value computed by B shall either equal the value computed by A, or be the value stored by side effect Y, where Y follows X in the modification order of M.
5.1.2.4p20:
NOTE 1 This effectively disallows compiler reordering of atomic operations to a single object, even if both operations are "relaxed" loads. By doing so, we effectively make the "cache coherence" guarantee provided by most hardware available to C atomic operations.
5.1.2.4p21:
NOTE 2 The visible sequence depends on the "happens before" relation, which depends on the values observed by loads of atomics, which we are restricting here. The intended reading is that there must exist an association of atomic loads with modifications they observe that, together with suitably chosen modification orders and the "happens before" relation derived as described above, satisfy the resulting constraints as imposed here.
5.1.2.4p22:
The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.
5.1.2.4p23:
NOTE 1 It can be shown that programs that correctly use simple locks to prevent all data races, and use no other synchronization operations, behave as though the executions of their constituent threads were simply interleaved, with each observed value of an object being the last value assigned in that interleaving. This is normally referred to as "sequential consistency". However, this applies only to race-free programs, and race-free programs cannot observe most program transformations that do not change single-threaded program semantics. In fact, most single-threaded program transformations continue to be allowed, since any program that behaves differently as a result must perform an undefined operation.
5.1.2.4p24:
NOTE 2 Compiler transformations that introduce assignments to a potentially shared memory location that would not be modified by the abstract machine are generally precluded by this standard, since such an assignment might overwrite another assignment by a different thread in cases in which an abstract machine execution would not have encountered a data race. This includes implementations of data member assignment that overwrite adjacent members in separate memory locations. We also generally preclude reordering of atomic loads in cases in which the atomics in question may alias, since this may violate the "visible sequence" rules.
5.1.2.4p25:
NOTE 3 Transformations that introduce a speculative read of a potentially shared memory location may not preserve the semantics of the C program as defined in this standard, since they potentially introduce a data race. However, they are typically valid in the context of an optimizing compiler that targets a specific machine with well-defined semantics for data races. They would be invalid for a hypothetical machine that is not tolerant of races or provides hardware race detection.
Add a new paragraph as 6.8.5p6:
An iteration statement that
- performs no I/O operations, and
- does not access or modify volatile objects, and
- performs no synchronization or atomic operations
in its body, controlling expression, or, in the case of a
for
statement, its expression-3, may be assumed by the implementation to terminate. « Footnote: This is intended to allow compiler transformations, such as removal of empty loops, even when termination cannot be proven. »
<stdatomic.h>
Add a new library subclause with the following paragraphs and subclauses. «ATM» will be used to refer to the number of this new section.
«ATM»p1:
The header
<stdatomic.h>
defines three macros and declares several types and functions for performing atomic operations on data shared between threads.
«ATM»p2:
The macros defined are
ATOMIC_INTEGRAL_LOCK_FREE ATOMIC_ADDRESS_LOCK_FREEwhich indicate the general lock-free property of integer and address atomic types; and
ATOMIC_FLAG_INITwhich expands to an initializer for an object of type
atomic_flag
.
«ATM»p3:
The types include
memory_orderwhich is an enumerated type whose enumerators identify memory ordering constraints;
atomic_flagwhich is structure type representing a lock-free, primitive atomic flag;
atomic_boolwhich is a structure type representing the atomic analog of the type
_Bool
;atomic_addresswhich is a structure type representing the atomic analog of a pointer type; and several atomic analogs of integer types.
«ATM».1p1:
The enumeration
memory_order
specifies the detailed regular (non-atomic) memory synchronization operations as defined in 5.1.2.4 and may provide for operation ordering. Its enumerated values are as follows:memory_order_relaxed memory_order_acquire memory_order_release memory_order_acq_rel memory_order_seq_cst
«ATM».1p2:
Their meanings are as follows.
memory_order_relaxed
- no operation orders memory.
memory_order_release
,memory_order_acq_rel
, andmemory_order_seq_cst
- a store operation performs a release operation on the affected memory location.
memory_order_acquire
,memory_order_acq_rel
, andmemory_order_seq_cst
- a load operation performs an acquire operation on the affected memory location.
«ATM».1p3:
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 eachmemory_order_seq_cst
operation that loads a value observes either the last preceding modification according to this order S, or the result of an operation that is notmemory_order_seq_cst
.
«ATM».1p4:
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.
«ATM».1p5:
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 lastmemory_order_seq_cst
modification of M preceding X in the total order S or a later modification of M in its modification order.
«ATM».1p6:
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.
«ATM».1p7:
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.
«ATM».1p8:
An atomic store shall only store a value that has been computed from constants and program input values by a finite sequence of program evaluations, such that each evaluation observes the values of variables as computed by the last prior assignment in the sequence. « Footnote: Among other implications, atomic variables shall not decay. » The ordering of evaluations in this sequence shall be such that
- If an evaluation B observes a value computed by A in a different thread, then B does not happen before A.
- If an evaluation A is included in the sequence, then all evaluations that assign to the same variable and happens before A is included.
«ATM».1p9:
NOTE The second requirement disallows "out-of-thin-air", or "speculative" stores of atomics when relaxed atomics are used. Since unordered operations are involved, evaluations may appear in this sequence out of thread order. For example, with
x
andy
initially zero,
- // Thread 1:
r1 = atomic_load_explicit(&y, memory_order_relaxed);
atomic_store_explicit(&x, r1, memory_order_relaxed);
- // Thread 2:
r2 = atomic_load_explicit(&x, memory_order_relaxed);
atomic_store_explicit(&y, 42, memory_order_relaxed);
is allowed to produce
r1 == 42 && r2 == 42
. The sequence of evaluations justifying this consists of:atomic_store_explicit(&y, 42, memory_order_relaxed); r1 = atomic_load_explicit(&y, memory_order_relaxed); atomic_store_explicit(&x, r1, memory_order_relaxed); r2 = atomic_load_explicit(&x, memory_order_relaxed);On the other hand,
- // Thread 1:
r1 = atomic_load_explicit(&y, memory_order_relaxed);
atomic_store_explicit(&x, r1, memory_order_relaxed);
- // Thread 2:
r2 = atomic_load_explicit(&x, memory_order_relaxed);
atomic_store_explicit(&y, r2, memory_order_relaxed);
may not produce
r1 == 42 && r2 = 42
, since there is no sequence of evaluations that results in the computation of 42. In the absence of "relaxed" operations and read-modify-write operations with weaker thanmemory_order_acq_rel
ordering, the second requirement has no impact.Recommended practice
«ATM».1p10:
The requirements do not forbid
r1 == 42 && r2 == 42
in the following example, withx
andy
initially zero:
- // Thread 1:
r1 = atomic_load_explicit(&x, memory_order_relaxed);
if (r1 == 42) atomic_store_explicit(&y, r1, memory_order_relaxed);
- // Thread 2:
r2 = atomic_load_explicit(&y, memory_order_relaxed);
if (r2 == 42) atomic_store_explicit(&x, 42, memory_order_relaxed);
However, this is not useful behavior, and implementations should not allow it.
«ATM».1p11:
Implementations should make atomic stores visible to atomic loads within a reasonable amount of time. Implementations shall not move an atomic operation out of an unbounded loop.
«ATM».2p1:
This subclause introduces synchronization primitives called fences. Fences can have acquire semantics, release semantics, or both. A fence with acquire semantics is called an acquire fence. A fence with release semantics is called a release fence.
«ATM».2p2:
A release fence A synchronizes with an acquire fence B if there exist atomic operations X and Y, both operating on some atomic object M, such that A is sequenced before X, X modifies M, Y is sequenced before B, and Y reads the value written by X or a value written by any side effect in the hypothetical release sequence X would head if it were a release operation.
«ATM».2p3:
A release fence A synchronizes with an atomic operation B that performs an acquire operation on an atomic object M if there exists an atomic operation X such that A is sequenced before X, X modifies M, and B reads the value written by X or a value written by any side effect in the hypothetical release sequence X would head if it were a release operation.
«ATM».2p4:
An atomic operation A that is a release operation on an atomic object M synchronizes with an acquire fence B if there exists some atomic operation X on M such that X is sequenced before B and reads the value written by A or a value written by any side effect in the release sequence headed by A.
atomic_thread_fence
functionSynopsis
«ATM».2.1p1:
#include <stdatomic.h> void atomic_thread_fence(memory_order order);Description
«ATM».2.1p2:
Depending on the value of
order
, this operation:
- has no effects, if
order == memory_order_relaxed
;- is an acquire fence, if
order == memory_order_acquire
;- is a release fence, if
order == memory_order_release
;- is both an acquire fence and a release fence, if
order == memory_order_acq_rel
;- is a sequentially consistent acquire and release fence, if
order == memory_order_seq_cst
.
atomic_signal_fence
functionSynopsis
«ATM».2.2p1:
#include <stdatomic.h> void atomic_signal_fence(memory_order order);Description
«ATM».2.2p2:
Equivalent to
atomic_thread_fence(order)
, except that "synchronizes with" relationships are established only between a thread and a signal handler executed in the same thread.
«ATM».2.2p3:
NOTE 1
atomic_signal_fence
can be used to specify the order in which actions performed by the thread become visible to the signal handler.
«ATM».2.2p4:
NOTE 2 Compiler optimizations and reorderings of loads and stores are inhibited in the same way as with
atomic_thread_fence
, but the hardware fence instructions thatatomic_thread_fence
would have inserted are not emitted.
«ATM».3p1:
The macros
ATOMIC_INTEGRAL_LOCK_FREE
andATOMIC_ADDRESS_LOCK_FREE
indicates the general lock-free property of integer and address atomic types. A value of 0 indicates that the types are never lock-free. A value of 1 indicates that the types are sometimes lock-free. A value of 2 indicates that the types are always lock-free.
«ATM».3p2:
NOTE Operations that are lock-free should also be also address-free. That is, atomic operations on the same memory location via two different addresses will communicate atomically. The implementation shall not depend on any per-process state. This restriction enables communication via memory mapped into a process more than once and memory shared between two processes.
atomic_is_lock_free
generic functionSynopsis
«ATM».3.1p1:
#include <stdatomic.h> _Bool atomic_is_lock_free(atomic_type const volatile *object);Description
«ATM».3.1p2:
The function
atomic_is_lock_free
indicates whether or not the object is lock-free. atomic_type can be any atomic type.Returns
«ATM».3.1p3:
True if the object's operations are lock-free, false otherwise. The result of a lock-free query on one object cannot be inferred from the result of a lock-free query on another object.
«ATM».4p1:
For each line in the following table, the atomic type name is declared as the name of a structure type which is the atomic analog of the corresponding integer type.
Atomic type name Integer type atomic_char char atomic_schar signed char atomic_uchar unsigned char atomic_short short atomic_ushort unsigned short atomic_int int atomic_uint unsigned int atomic_long long atomic_ulong unsigned long atomic_llong long long atomic_ullong unsigned long long
«ATM».4p2:
For each line in the following table, the atomic type name is declared as a structure type which is the atomic analog of the corresponding integer typedef.
Atomic type name Integer typedef atomic_char16_t char16_t atomic_char32_t char32_t atomic_wchar_t wchar_t atomic_int_least8_t int_least8_t atomic_uint_least8_t uint_least8_t atomic_int_least16_t int_least16_t atomic_uint_least16_t uint_least16_t atomic_int_least32_t int_least32_t atomic_uint_least32_t uint_least32_t atomic_int_least64_t int_least64_t atomic_uint_least64_t uint_least64_t atomic_int_fast8_t int_fast8_t atomic_uint_fast8_t uint_fast8_t atomic_int_fast16_t int_fast16_t atomic_uint_fast16_t uint_fast16_t atomic_int_fast32_t int_fast32_t atomic_uint_fast32_t uint_fast32_t atomic_int_fast64_t int_fast64_t atomic_uint_fast64_t uint_fast64_t atomic_intptr_t intptr_t atomic_uintptr_t uintptr_t atomic_size_t size_t atomic_ssize_t ssize_t atomic_ptrdiff_t ptrdiff_t atomic_intmax_t intmax_t atomic_uintmax_t uintmax_t
«ATM».4p3:
The semantics of the operations on these types are defined in «ATM».5.
«ATM».4p4:
The
atomic_bool
type provides an atomic boolean.
«ATM».4p5:
The
atomic_address
type provides atomicvoid*
operations. The unit of addition/subtraction shall be one byte.
«ATM».4p6:
NOTE The representation of atomic integer and address types need not have the same size as their corresponding regular types. They should have the same size whenever possible, as it eases effort required to port existing code.
«ATM».5p1:
There are only a few kinds of operations on atomic types, though there are many instances on those kinds. This section specifies each general kind.
«ATM».5p2:
In the following operation definitions:
- An
A
refers to one of the atomic types.- A
C
refers to its corresponding non-atomic type. Theatomic_address
atomic type corresponds to thevoid*
non-atomic type.- A
M
refers to type of the other argument for arithmetic operations. For atomic integer types,M
isC
. For atomic address types,M
isptrdiff_t
.- The functions not ending in
_explicit
have the semantics of their corresponding_explicit
withmemory_order
arguments ofmemory_order_seq_cst
.
«ATM».5p3: [last two sentences deleted]
NOTE Many operations are volatile-qualified. The "volatile as device register" semantics have not changed in the standard. This qualification means that volatility is preserved when applying these operations to volatile objects.
atomic_store
generic functionsSynopsis
«ATM».5.1p1:
#include <stdatomic.h> void atomic_store(volatile A *object, C desired); void atomic_store_explicit(volatile A *object, C desired, memory_order order);Description
«ATM».5.1p2:
The
order
argument shall not bememory_order_acquire
, normemory_order_acq_rel
. Atomically replace the value pointed to byobject
with the value ofdesired
. Memory is affected according to the value oforder
.
atomic_load
generic functionsSynopsis
«ATM».5.2p1:
#include <stdatomic.h> C atomic_load(volatile A *object); C atomic_load_explicit(volatile A *object, memory_order order);Description
«ATM».5.2p2:
The
order
argument shall not bememory_order_release
normemory_order_acq_rel
. Memory is affected according to the value oforder
.Returns
Atomically returns the value pointed to by
object
.
atomic_exchange
generic functionsSynopsis
«ATM».5.3p1:
#include <stdatomic.h> C atomic_exchange(volatile A *object, C desired); C atomic_exchange_explicit(volatile A *object, C desired, memory_order order);Description
«ATM».5.3p2:
Atomically replace the value pointed to by
object
withdesired
. Memory is affected according to the value oforder
. These operations are read-modify-write operations (5.1.2.4).Returns
«ATM».5.3p3:
Atomically returns the value pointed to by
object
immediately before the effects.
atomic_compare_exchange
generic functionsSynopsis
«ATM».5.4p1:
#include <stdatomic.h> _Bool atomic_compare_exchange_strong(volatile A *object, C *expected, C desired); _Bool atomic_compare_exchange_strong_explicit(volatile A *object, C *expected, C desired, memory_order success, memory_order failure); _Bool atomic_compare_exchange_weak(volatile A *object, C *expected, C desired); _Bool atomic_compare_exchange_weak_explicit(volatile A *object, C *expected, C desired, memory_order success, memory_order failure);Description
«ATM».5.4p2:
The
failure
argument shall not bememory_order_release
normemory_order_acq_rel
. Thefailure
argument shall be no stronger than thesuccess
argument. Atomically, compares the value pointed to byobject
for equality with that inexpected
, and if true, replaces the value pointed to byobject
withdesired
, and if false, updates the value inexpected
with the value pointed to byobject
. Further, if the comparison is true, memory is affected according to the value ofsuccess
, and if the comparison is false, memory is affected according to the value offailure
. These operations are atomic read-modify-write operations (5.1.2.4).
«ATM».5.4p2:
NOTE The effect of the compare-and-exchange operations is
if (*object == *expected) *object = desired; else *expected = *object;
«ATM».5.4p3:
The weak compare-and-exchange operations may fail spuriously, that is, return false while leaving the value pointed to by
expected
unchanged.
«ATM».5.4p4:
NOTE This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g. load-locked store-conditional machines.
«ATM».5.4p5:
EXAMPLE A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop.
expected = atomic_load(¤t); do desired = function(expected); while (!atomic_compare_exchange(¤t, expected, desired));
When a compare-and-exchange is in a loop, the weak version will yield better performance on some platforms. When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable.
Returns
«ATM».5.4p6:
The result of the comparison.
atomic_fetch
-and-modify generic functions«ATM».5.5p1:
The following operations perform arithmetic and bitwise computations. All of these operations are applicable to an object of any atomic integer type. Only addition and subtraction are applicable to
atomic_address
. None of these operations is applicable toatomic_bool
. The key, operator, and computation correspondence is:
key
op computation key
op computation add
+
addition sub
-
subtraction or
|
bitwise inclusive or xor
^
bitwise exclusive or and
&
bitwise and Synopsis
«ATM».5.5p2:
#include <stdatomic.h> C atomic_fetch_key(volatile A *object, M operand); C atomic_fetch_key_explicit(volatile A *object, M operand, memory_order order);Description
«ATM».5.5p3:
Atomically replaces the value pointed to by
object
with the result of the computation applied to the value pointed to byobject
and the given operand. Memory is affected according to the value oforder
. These operations are atomic read-modify-write operations (5.1.2.4). For signed integer types, arithmetic is defined to use two's-complement representation. There are no undefined results. For address types, the result may be an undefined address, but the operations otherwise have no undefined behavior.Returns
«ATM».5.5p4:
Atomically, the value pointed to by
object
immediately before the effects.
«ATM».5.5p5:
NOTE The operation of an
atomic_fetch_key
function is nearly equivalent to the operation of the corresponding op= compound assignment operator. The only differences are that a compound assignment operator is not guaranteed to operate atomically, and that the result of a compound assignment operation is the updated value of the object, whereas the value returned by anatomic_fetch_key
function is the previous value of the atomic object.
«ATM».6p1:
The
atomic_flag
type provides the classic test-and-set functionality. It has two states, set and clear.
«ATM».6p2:
Operations on an object of type
atomic_flag
shall be lock free.
«ATM».6p3:
NOTE Hence the operations should also be address-free. No other type requires lock-free operations, so the
atomic_flag
type is the minimum hardware-implemented type needed to conform to this International standard. The remaining types can be emulated withatomic_flag
, though with less than ideal properties.
«ATM».6p4:
The macro
ATOMIC_FLAG_INIT
may be used to initialize anatomic_flag
to the clear state. Anatomic_flag
that is not explicitly initialized withATOMIC_FLAG_INIT
is initially in an indeterminate state.
«ATM».6p5:
EXAMPLE
atomic_flag guard = ATOMIC_FLAG_INIT;
atomic_flag_test_and_set
functionsSynopsis
«ATM».6.1p1:
#include <stdatomic.h> bool atomic_flag_test_and_set(volatile atomic_flag *object); bool atomic_flag_test_and_set_explicit(volatile atomic_flag *object, memory_order order);Description
«ATM».6.1p2:
Atomically sets the value pointed to by
object
to true. Memory is affected according to the value oforder
. These operations are atomic read-modify-write operations (5.1.2.4).Returns
«ATM».6.1p3:
Atomically, the value of the object immediately before the effects.
atomic_flag_clear
functionsSynopsis
«ATM».6.2p1:
#include <stdatomic.h> void atomic_flag_clear(volatile atomic_flag *object); void atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order);Description
«ATM».6.2p2:
The
order
argument shall not bememory_order_acquire
normemory_order_acq_rel
. Atomically sets the value pointed to byobject
to false. Memory is affected according to the value oforder
.