4054 lines
212 KiB
Markdown
4054 lines
212 KiB
Markdown
[atomics]
|
||
|
||
# 32 Concurrency support library [[thread]](./#thread)
|
||
|
||
## 32.5 Atomic operations [atomics]
|
||
|
||
### [32.5.1](#general) General [[atomics.general]](atomics.general)
|
||
|
||
[1](#general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2388)
|
||
|
||
Subclause [atomics] describes components for fine-grained atomic access[.](#general-1.sentence-1)
|
||
|
||
This access is provided via operations on atomic objects[.](#general-1.sentence-2)
|
||
|
||
### [32.5.2](#syn) Header <atomic> synopsis [[atomics.syn]](atomics.syn)
|
||
|
||
[ð](#header:%3catomic%3e)
|
||
|
||
namespace std {// [[atomics.order]](#order "32.5.4 Order and consistency"), order and consistencyenum class memory_order : *unspecified*; // freestandinginline constexpr memory_order memory_order_relaxed = memory_order::relaxed; // freestandinginline constexpr memory_order memory_order_acquire = memory_order::acquire; // freestandinginline constexpr memory_order memory_order_release = memory_order::release; // freestandinginline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel; // freestandinginline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst; // freestanding}// [[atomics.lockfree]](#lockfree "32.5.5 Lock-free property"), lock-free property#define ATOMIC_BOOL_LOCK_FREE *unspecified* // freestanding#define ATOMIC_CHAR_LOCK_FREE *unspecified* // freestanding#define ATOMIC_CHAR8_T_LOCK_FREE *unspecified* // freestanding#define ATOMIC_CHAR16_T_LOCK_FREE *unspecified* // freestanding#define ATOMIC_CHAR32_T_LOCK_FREE *unspecified* // freestanding#define ATOMIC_WCHAR_T_LOCK_FREE *unspecified* // freestanding#define ATOMIC_SHORT_LOCK_FREE *unspecified* // freestanding#define ATOMIC_INT_LOCK_FREE *unspecified* // freestanding#define ATOMIC_LONG_LOCK_FREE *unspecified* // freestanding#define ATOMIC_LLONG_LOCK_FREE *unspecified* // freestanding#define ATOMIC_POINTER_LOCK_FREE *unspecified* // freestandingnamespace std {// [[atomics.ref.generic]](#ref.generic "32.5.7 Class template atomic_ref"), class template atomic_reftemplate<class T> struct atomic_ref; // freestanding// [[atomics.types.generic]](#types.generic "32.5.8 Class template atomic"), class template atomictemplate<class T> struct atomic; // freestanding// [[atomics.types.pointer]](#types.pointer "32.5.8.5 Partial specialization for pointers"), partial specialization for pointerstemplate<class T> struct atomic<T*>; // freestanding// [[atomics.nonmembers]](#nonmembers "32.5.9 Non-member functions"), non-member functionstemplate<class T>bool atomic_is_lock_free(const volatile atomic<T>*) noexcept; // freestandingtemplate<class T>bool atomic_is_lock_free(const atomic<T>*) noexcept; // freestandingtemplate<class T>void atomic_store(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr void atomic_store(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>void atomic_store_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type, memory_order) noexcept; template<class T>constexpr void atomic_store_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type, memory_order) noexcept; template<class T> T atomic_load(const volatile atomic<T>*) noexcept; // freestandingtemplate<class T>constexpr T atomic_load(const atomic<T>*) noexcept; // freestandingtemplate<class T> T atomic_load_explicit(const volatile atomic<T>*, memory_order) noexcept; // freestandingtemplate<class T>constexpr T atomic_load_explicit(const atomic<T>*, memory_order) noexcept; // freestandingtemplate<class T> T atomic_exchange(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr T atomic_exchange(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T> T atomic_exchange_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type, memory_order) noexcept; template<class T>constexpr T atomic_exchange_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>bool atomic_compare_exchange_weak(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type*, typename atomic<T>::value_type) noexcept; template<class T>constexpr bool atomic_compare_exchange_weak(atomic<T>*, // freestandingtypename atomic<T>::value_type*, typename atomic<T>::value_type) noexcept; template<class T>bool atomic_compare_exchange_strong(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type*, typename atomic<T>::value_type) noexcept; template<class T>constexpr bool atomic_compare_exchange_strong(atomic<T>*, // freestandingtypename atomic<T>::value_type*, typename atomic<T>::value_type) noexcept; template<class T>bool atomic_compare_exchange_weak_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type*, typename atomic<T>::value_type,
|
||
memory_order, memory_order) noexcept; template<class T>constexpr bool atomic_compare_exchange_weak_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type*, typename atomic<T>::value_type,
|
||
memory_order, memory_order) noexcept; template<class T>bool atomic_compare_exchange_strong_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type*, typename atomic<T>::value_type,
|
||
memory_order, memory_order) noexcept; template<class T>constexpr bool atomic_compare_exchange_strong_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type*, typename atomic<T>::value_type,
|
||
memory_order, memory_order) noexcept; template<class T> T atomic_fetch_add(volatile atomic<T>*, // freestandingtypename atomic<T>::difference_type) noexcept; template<class T>constexpr T atomic_fetch_add(atomic<T>*, // freestandingtypename atomic<T>::difference_type) noexcept; template<class T> T atomic_fetch_add_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::difference_type,
|
||
memory_order) noexcept; template<class T>constexpr T atomic_fetch_add_explicit(atomic<T>*, // freestandingtypename atomic<T>::difference_type,
|
||
memory_order) noexcept; template<class T> T atomic_fetch_sub(volatile atomic<T>*, // freestandingtypename atomic<T>::difference_type) noexcept; template<class T>constexpr T atomic_fetch_sub(atomic<T>*, // freestandingtypename atomic<T>::difference_type) noexcept; template<class T> T atomic_fetch_sub_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::difference_type,
|
||
memory_order) noexcept; template<class T>constexpr T atomic_fetch_sub_explicit(atomic<T>*, // freestandingtypename atomic<T>::difference_type,
|
||
memory_order) noexcept; template<class T> T atomic_fetch_and(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr T atomic_fetch_and(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T> T atomic_fetch_and_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>constexpr T atomic_fetch_and_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T> T atomic_fetch_or(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr T atomic_fetch_or(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T> T atomic_fetch_or_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>constexpr T atomic_fetch_or_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T> T atomic_fetch_xor(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr T atomic_fetch_xor(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T> T atomic_fetch_xor_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>constexpr T atomic_fetch_xor_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T> T atomic_fetch_max(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr T atomic_fetch_max(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T> T atomic_fetch_max_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>constexpr T atomic_fetch_max_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T> T atomic_fetch_min(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr T atomic_fetch_min(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T> T atomic_fetch_min_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>constexpr T atomic_fetch_min_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>void atomic_store_add(volatile atomic<T>*, // freestandingtypename atomic<T>::difference_type) noexcept; template<class T>constexpr void atomic_store_add(atomic<T>*, // freestandingtypename atomic<T>::difference_type) noexcept; template<class T>void atomic_store_add_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::difference_type, memory_order) noexcept; template<class T>constexpr void atomic_store_add_explicit(atomic<T>*, // freestandingtypename atomic<T>::difference_type,
|
||
memory_order) noexcept; template<class T>void atomic_store_sub(volatile atomic<T>*, // freestandingtypename atomic<T>::difference_type) noexcept; template<class T>constexpr void atomic_store_sub(atomic<T>*, // freestandingtypename atomic<T>::difference_type) noexcept; template<class T>void atomic_store_sub_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::difference_type, memory_order) noexcept; template<class T>constexpr void atomic_store_sub_explicit(atomic<T>*, // freestandingtypename atomic<T>::difference_type,
|
||
memory_order) noexcept; template<class T>void atomic_store_and(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr void atomic_store_and(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>void atomic_store_and_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type, memory_order) noexcept; template<class T>constexpr void atomic_store_and_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>void atomic_store_or(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr void atomic_store_or(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>void atomic_store_or_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type, memory_order) noexcept; template<class T>constexpr void atomic_store_or_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>void atomic_store_xor(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr void atomic_store_xor(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>void atomic_store_xor_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type, memory_order) noexcept; template<class T>constexpr void atomic_store_xor_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>void atomic_store_max(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr void atomic_store_max(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>void atomic_store_max_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type, memory_order) noexcept; template<class T>constexpr void atomic_store_max_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>void atomic_store_min(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr void atomic_store_min(atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>void atomic_store_min_explicit(volatile atomic<T>*, // freestandingtypename atomic<T>::value_type, memory_order) noexcept; template<class T>constexpr void atomic_store_min_explicit(atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>void atomic_wait(const volatile atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>constexpr void atomic_wait(const atomic<T>*, // freestandingtypename atomic<T>::value_type) noexcept; template<class T>void atomic_wait_explicit(const volatile atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>constexpr void atomic_wait_explicit(const atomic<T>*, // freestandingtypename atomic<T>::value_type,
|
||
memory_order) noexcept; template<class T>void atomic_notify_one(volatile atomic<T>*) noexcept; // freestandingtemplate<class T>constexpr void atomic_notify_one(atomic<T>*) noexcept; // freestandingtemplate<class T>void atomic_notify_all(volatile atomic<T>*) noexcept; // freestandingtemplate<class T>constexpr void atomic_notify_all(atomic<T>*) noexcept; // freestanding// [[atomics.alias]](#alias "32.5.3 Type aliases"), type aliasesusing atomic_bool = atomic<bool>; // freestandingusing atomic_char = atomic<char>; // freestandingusing atomic_schar = atomic<signed char>; // freestandingusing atomic_uchar = atomic<unsigned char>; // freestandingusing atomic_short = atomic<short>; // freestandingusing atomic_ushort = atomic<unsigned short>; // freestandingusing atomic_int = atomic<int>; // freestandingusing atomic_uint = atomic<unsigned int>; // freestandingusing atomic_long = atomic<long>; // freestandingusing atomic_ulong = atomic<unsigned long>; // freestandingusing atomic_llong = atomic<long long>; // freestandingusing atomic_ullong = atomic<unsigned long long>; // freestandingusing atomic_char8_t = atomic<char8_t>; // freestandingusing atomic_char16_t = atomic<char16_t>; // freestandingusing atomic_char32_t = atomic<char32_t>; // freestandingusing atomic_wchar_t = atomic<wchar_t>; // freestandingusing atomic_int8_t = atomic<int8_t>; // freestandingusing atomic_uint8_t = atomic<uint8_t>; // freestandingusing atomic_int16_t = atomic<int16_t>; // freestandingusing atomic_uint16_t = atomic<uint16_t>; // freestandingusing atomic_int32_t = atomic<int32_t>; // freestandingusing atomic_uint32_t = atomic<uint32_t>; // freestandingusing atomic_int64_t = atomic<int64_t>; // freestandingusing atomic_uint64_t = atomic<uint64_t>; // freestandingusing atomic_int_least8_t = atomic<int_least8_t>; // freestandingusing atomic_uint_least8_t = atomic<uint_least8_t>; // freestandingusing atomic_int_least16_t = atomic<int_least16_t>; // freestandingusing atomic_uint_least16_t = atomic<uint_least16_t>; // freestandingusing atomic_int_least32_t = atomic<int_least32_t>; // freestandingusing atomic_uint_least32_t = atomic<uint_least32_t>; // freestandingusing atomic_int_least64_t = atomic<int_least64_t>; // freestandingusing atomic_uint_least64_t = atomic<uint_least64_t>; // freestandingusing atomic_int_fast8_t = atomic<int_fast8_t>; // freestandingusing atomic_uint_fast8_t = atomic<uint_fast8_t>; // freestandingusing atomic_int_fast16_t = atomic<int_fast16_t>; // freestandingusing atomic_uint_fast16_t = atomic<uint_fast16_t>; // freestandingusing atomic_int_fast32_t = atomic<int_fast32_t>; // freestandingusing atomic_uint_fast32_t = atomic<uint_fast32_t>; // freestandingusing atomic_int_fast64_t = atomic<int_fast64_t>; // freestandingusing atomic_uint_fast64_t = atomic<uint_fast64_t>; // freestandingusing atomic_intptr_t = atomic<intptr_t>; // freestandingusing atomic_uintptr_t = atomic<uintptr_t>; // freestandingusing atomic_size_t = atomic<size_t>; // freestandingusing atomic_ptrdiff_t = atomic<ptrdiff_t>; // freestandingusing atomic_intmax_t = atomic<intmax_t>; // freestandingusing atomic_uintmax_t = atomic<uintmax_t>; // freestandingusing atomic_signed_lock_free = *see below*; using atomic_unsigned_lock_free = *see below*; // [[atomics.flag]](#flag "32.5.10 Flag type and operations"), flag type and operationsstruct atomic_flag; // freestandingbool atomic_flag_test(const volatile atomic_flag*) noexcept; // freestandingconstexpr bool atomic_flag_test(const atomic_flag*) noexcept; // freestandingbool atomic_flag_test_explicit(const volatile atomic_flag*, // freestanding memory_order) noexcept; constexpr bool atomic_flag_test_explicit(const atomic_flag*, // freestanding memory_order) noexcept; bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; // freestandingconstexpr bool atomic_flag_test_and_set(atomic_flag*) noexcept; // freestandingbool atomic_flag_test_and_set_explicit(volatile atomic_flag*, // freestanding memory_order) noexcept; constexpr bool atomic_flag_test_and_set_explicit(atomic_flag*, // freestanding memory_order) noexcept; void atomic_flag_clear(volatile atomic_flag*) noexcept; // freestandingconstexpr void atomic_flag_clear(atomic_flag*) noexcept; // freestandingvoid atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; // freestandingconstexpr void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; // freestandingvoid atomic_flag_wait(const volatile atomic_flag*, bool) noexcept; // freestandingconstexpr void atomic_flag_wait(const atomic_flag*, bool) noexcept; // freestandingvoid atomic_flag_wait_explicit(const volatile atomic_flag*, // freestandingbool, memory_order) noexcept; constexpr void atomic_flag_wait_explicit(const atomic_flag*, // freestandingbool, memory_order) noexcept; void atomic_flag_notify_one(volatile atomic_flag*) noexcept; // freestandingconstexpr void atomic_flag_notify_one(atomic_flag*) noexcept; // freestandingvoid atomic_flag_notify_all(volatile atomic_flag*) noexcept; // freestandingconstexpr void atomic_flag_notify_all(atomic_flag*) noexcept; // freestanding#define ATOMIC_FLAG_INIT *see below* // freestanding// [[atomics.fences]](#fences "32.5.11 Fences"), fencesextern "C" constexpr void atomic_thread_fence(memory_order) noexcept; // freestandingextern "C" constexpr void atomic_signal_fence(memory_order) noexcept; // freestanding}
|
||
|
||
### [32.5.3](#alias) Type aliases [[atomics.alias]](atomics.alias)
|
||
|
||
[1](#alias-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2857)
|
||
|
||
The type aliases atomic_intN_t, atomic_uintN_t,atomic_intptr_t, and atomic_uintptr_t are defined if and only ifintN_t, uintN_t,intptr_t, and uintptr_t are defined, respectively[.](#alias-1.sentence-1)
|
||
|
||
[2](#alias-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2865)
|
||
|
||
The type aliasesatomic_signed_lock_free and atomic_unsigned_lock_free name specializations of atomic whose template arguments are integral types, respectively signed and unsigned,
|
||
and whose is_always_lock_free property is true[.](#alias-2.sentence-1)
|
||
|
||
[*Note [1](#alias-note-1)*:
|
||
|
||
These aliases are optional in freestanding implementations ([[compliance]](compliance "16.4.2.5 Freestanding implementations"))[.](#alias-2.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
Implementations should choose for these aliases
|
||
the integral specializations of atomic for which the atomic waiting and notifying operations ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))
|
||
are most efficient[.](#alias-2.sentence-3)
|
||
|
||
### [32.5.4](#order) Order and consistency [[atomics.order]](atomics.order)
|
||
|
||
namespace std {enum class memory_order : *unspecified* { relaxed = 0, acquire = 2, release = 3, acq_rel = 4, seq_cst = 5};}
|
||
|
||
[1](#order-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2903)
|
||
|
||
The enumeration memory_order specifies the detailed regular
|
||
(non-atomic) memory synchronization order as defined in[[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races") and may provide for operation ordering[.](#order-1.sentence-1)
|
||
|
||
Its
|
||
enumerated values and their meanings are as follows:
|
||
|
||
- [(1.1)](#order-1.1)
|
||
|
||
memory_order::relaxed: no operation orders memory[.](#order-1.1.sentence-1)
|
||
|
||
- [(1.2)](#order-1.2)
|
||
|
||
memory_order::release, memory_order::acq_rel, andmemory_order::seq_cst: a store operation performs a release operation on the
|
||
affected memory location[.](#order-1.2.sentence-1)
|
||
|
||
- [(1.3)](#order-1.3)
|
||
|
||
memory_order::acquire, memory_order::acq_rel, andmemory_order::seq_cst: a load operation performs an acquire operation on the
|
||
affected memory location[.](#order-1.3.sentence-1)
|
||
|
||
[*Note [1](#order-note-1)*:
|
||
|
||
Atomic operations specifying memory_order::relaxed are relaxed
|
||
with respect to memory ordering[.](#order-1.sentence-3)
|
||
|
||
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[.](#order-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[2](#order-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2928)
|
||
|
||
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[.](#order-2.sentence-1)
|
||
|
||
[3](#order-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2934)
|
||
|
||
An atomic operation A on some atomic object M is[*coherence-ordered before*](#def:coherence-ordered_before "32.5.4 Order and consistency [atomics.order]") another atomic operation B on M if
|
||
|
||
- [(3.1)](#order-3.1)
|
||
|
||
A is a modification, andB reads the value stored by A, or
|
||
|
||
- [(3.2)](#order-3.2)
|
||
|
||
A precedes B in the modification order of M, or
|
||
|
||
- [(3.3)](#order-3.3)
|
||
|
||
A and B are not
|
||
the same atomic read-modify-write operation, and
|
||
there exists an atomic modification X of M such that A reads the value stored by X andX precedes B in the modification order of M, or
|
||
|
||
- [(3.4)](#order-3.4)
|
||
|
||
there exists an atomic modification X of M such that A is coherence-ordered before X andX is coherence-ordered before B[.](#order-3.sentence-1)
|
||
|
||
[4](#order-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2954)
|
||
|
||
There is a single total order S on all memory_order::seq_cst operations, including fences,
|
||
that satisfies the following constraints[.](#order-4.sentence-1)
|
||
|
||
First, if A and B arememory_order::seq_cst operations andA strongly happens before B,
|
||
then A precedes B in S[.](#order-4.sentence-2)
|
||
|
||
Second, for every pair of atomic operations A andB on an object M,
|
||
where A is coherence-ordered before B,
|
||
the following four conditions are required to be satisfied by S:
|
||
|
||
- [(4.1)](#order-4.1)
|
||
|
||
if A and B are bothmemory_order::seq_cst operations,
|
||
then A precedes B in S; and
|
||
|
||
- [(4.2)](#order-4.2)
|
||
|
||
if A is a memory_order::seq_cst operation andB happens before
|
||
a memory_order::seq_cst fence Y,
|
||
then A precedes Y in S; and
|
||
|
||
- [(4.3)](#order-4.3)
|
||
|
||
if a memory_order::seq_cst fence X happens before A andB is a memory_order::seq_cst operation,
|
||
then X precedes B in S; and
|
||
|
||
- [(4.4)](#order-4.4)
|
||
|
||
if a memory_order::seq_cst fence X happens before A andB happens before
|
||
a memory_order::seq_cst fence Y,
|
||
then X precedes Y in S[.](#order-4.sentence-3)
|
||
|
||
[5](#order-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2985)
|
||
|
||
[*Note [2](#order-note-2)*:
|
||
|
||
This definition ensures that S is consistent with
|
||
the modification order of any atomic object M[.](#order-5.sentence-1)
|
||
|
||
It also ensures that
|
||
a memory_order::seq_cst load A of M gets its value either from the last modification of M that precedes A in S or
|
||
from some non-memory_order::seq_cst modification of M that does not happen before any modification of M that precedes A in S[.](#order-5.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[6](#order-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L2998)
|
||
|
||
[*Note [3](#order-note-3)*:
|
||
|
||
We do not require that S be consistent with
|
||
âhappens beforeâ ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#order-6.sentence-1)
|
||
|
||
This allows more efficient implementation
|
||
of memory_order::acquire and memory_order::release on some machine architectures[.](#order-6.sentence-2)
|
||
|
||
It can produce surprising results
|
||
when these are mixed with memory_order::seq_cst accesses[.](#order-6.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[7](#order-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3009)
|
||
|
||
[*Note [4](#order-note-4)*:
|
||
|
||
memory_order::seq_cst ensures sequential consistency only
|
||
for a program that is free of data races and
|
||
uses exclusively memory_order::seq_cst atomic operations[.](#order-7.sentence-1)
|
||
|
||
Any use of weaker ordering will invalidate this guarantee
|
||
unless extreme care is used[.](#order-7.sentence-2)
|
||
|
||
In many cases, memory_order::seq_cst atomic operations are reorderable
|
||
with respect to other atomic operations performed by the same thread[.](#order-7.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[8](#order-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3020)
|
||
|
||
Implementations should ensure that no âout-of-thin-airâ values are computed that
|
||
circularly depend on their own computation[.](#order-8.sentence-1)
|
||
|
||
[*Note [5](#order-note-5)*:
|
||
|
||
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); this recommendation discourages producing 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[.](#order-8.sentence-3)
|
||
|
||
Note that without this restriction, such an
|
||
execution is possible[.](#order-8.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[9](#order-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3043)
|
||
|
||
[*Note [6](#order-note-6)*:
|
||
|
||
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*]
|
||
|
||
[10](#order-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3061)
|
||
|
||
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[.](#order-10.sentence-1)
|
||
|
||
[11](#order-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3066)
|
||
|
||
An [*atomic modify-write operation*](#def:modify-write_operation,atomic "32.5.4 Order and consistency [atomics.order]") is
|
||
an atomic read-modify-write operation
|
||
with weaker synchronization requirements as specified in [[atomics.fences]](#fences "32.5.11 Fences")[.](#order-11.sentence-1)
|
||
|
||
[*Note [7](#order-note-7)*:
|
||
|
||
The intent is for atomic modify-write operations
|
||
to be implemented using mechanisms that are not ordered, in hardware,
|
||
by the implementation of acquire fences[.](#order-11.sentence-2)
|
||
|
||
No other semantic or hardware property
|
||
(e.g., that the mechanism is a far atomic operation) is implied[.](#order-11.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[12](#order-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3078)
|
||
|
||
*Recommended practice*: The implementation should make atomic stores visible to atomic loads,
|
||
and atomic loads should observe atomic stores,
|
||
within a reasonable amount of time[.](#order-12.sentence-1)
|
||
|
||
### [32.5.5](#lockfree) Lock-free property [[atomics.lockfree]](atomics.lockfree)
|
||
|
||
[ð](#:values_of_various_ATOMIC_..._LOCK_FREE_macros)
|
||
|
||
#define ATOMIC_BOOL_LOCK_FREE *unspecified*#define ATOMIC_CHAR_LOCK_FREE *unspecified*#define ATOMIC_CHAR8_T_LOCK_FREE *unspecified*#define ATOMIC_CHAR16_T_LOCK_FREE *unspecified*#define ATOMIC_CHAR32_T_LOCK_FREE *unspecified*#define ATOMIC_WCHAR_T_LOCK_FREE *unspecified*#define ATOMIC_SHORT_LOCK_FREE *unspecified*#define ATOMIC_INT_LOCK_FREE *unspecified*#define ATOMIC_LONG_LOCK_FREE *unspecified*#define ATOMIC_LLONG_LOCK_FREE *unspecified*#define ATOMIC_POINTER_LOCK_FREE *unspecified*
|
||
|
||
[1](#lockfree-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3101)
|
||
|
||
The ATOMIC_..._LOCK_FREE macros indicate the lock-free property of the
|
||
corresponding atomic types, with the signed and unsigned variants grouped
|
||
together[.](#lockfree-1.sentence-1)
|
||
|
||
The properties also apply to the corresponding (partial) specializations of theatomic template[.](#lockfree-1.sentence-2)
|
||
|
||
A value of 0 indicates that the types are never
|
||
lock-free[.](#lockfree-1.sentence-3)
|
||
|
||
A value of 1 indicates that the types are sometimes lock-free[.](#lockfree-1.sentence-4)
|
||
|
||
A
|
||
value of 2 indicates that the types are always lock-free[.](#lockfree-1.sentence-5)
|
||
|
||
[2](#lockfree-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3109)
|
||
|
||
On a hosted implementation ([[compliance]](compliance "16.4.2.5 Freestanding implementations")),
|
||
at least one signed integral specialization of the atomic template,
|
||
along with the specialization
|
||
for the corresponding unsigned type ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")),
|
||
is always lock-free[.](#lockfree-2.sentence-1)
|
||
|
||
[3](#lockfree-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3116)
|
||
|
||
The functions atomic<T>::is_lock_free andatomic_is_lock_free ([[atomics.types.operations]](#types.operations "32.5.8.2 Operations on atomic types"))
|
||
indicate whether the object is lock-free[.](#lockfree-3.sentence-1)
|
||
|
||
In any given program execution, the
|
||
result of the lock-free query
|
||
is the same for all atomic objects of the same type[.](#lockfree-3.sentence-2)
|
||
|
||
[4](#lockfree-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3123)
|
||
|
||
Atomic operations that are not lock-free are considered to potentially
|
||
block ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))[.](#lockfree-4.sentence-1)
|
||
|
||
[5](#lockfree-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3127)
|
||
|
||
*Recommended practice*: Operations that are lock-free should also be address-free[.](#lockfree-5.sentence-1)[294](#footnote-294 "That is, atomic operations on the same memory location via two different addresses will communicate atomically.")
|
||
|
||
The implementation of these operations should not depend on any per-process state[.](#lockfree-5.sentence-2)
|
||
|
||
[*Note [1](#lockfree-note-1)*:
|
||
|
||
This restriction enables communication by memory that is
|
||
mapped into a process more than once and by memory that is shared between two
|
||
processes[.](#lockfree-5.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[294)](#footnote-294)[294)](#footnoteref-294)
|
||
|
||
That is,
|
||
atomic operations on the same memory location via two different addresses will
|
||
communicate atomically[.](#footnote-294.sentence-1)
|
||
|
||
### [32.5.6](#wait) Waiting and notifying [[atomics.wait]](atomics.wait)
|
||
|
||
[1](#wait-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3144)
|
||
|
||
[*Atomic waiting operations*](#def:atomic,waiting_operation "32.5.6 Waiting and notifying [atomics.wait]") and [*atomic notifying operations*](#def:atomic,notifying_operation "32.5.6 Waiting and notifying [atomics.wait]") provide a mechanism to wait for the value of an atomic object to change
|
||
more efficiently than can be achieved with polling[.](#wait-1.sentence-1)
|
||
|
||
An atomic waiting operation may block until it is unblocked
|
||
by an atomic notifying operation, according to each function's effects[.](#wait-1.sentence-2)
|
||
|
||
[*Note [1](#wait-note-1)*:
|
||
|
||
Programs are not guaranteed to observe transient atomic values,
|
||
an issue known as the A-B-A problem,
|
||
resulting in continued blocking if a condition is only temporarily met[.](#wait-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#wait-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3157)
|
||
|
||
[*Note [2](#wait-note-2)*:
|
||
|
||
The following functions are atomic waiting operations:
|
||
|
||
- [(2.1)](#wait-2.1)
|
||
|
||
atomic<T>::wait,
|
||
|
||
- [(2.2)](#wait-2.2)
|
||
|
||
atomic_flag::wait,
|
||
|
||
- [(2.3)](#wait-2.3)
|
||
|
||
atomic_wait and atomic_wait_explicit,
|
||
|
||
- [(2.4)](#wait-2.4)
|
||
|
||
atomic_flag_wait and atomic_flag_wait_explicit, and
|
||
|
||
- [(2.5)](#wait-2.5)
|
||
|
||
atomic_ref<T>::wait[.](#wait-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[3](#wait-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3169)
|
||
|
||
[*Note [3](#wait-note-3)*:
|
||
|
||
The following functions are atomic notifying operations:
|
||
|
||
- [(3.1)](#wait-3.1)
|
||
|
||
atomic<T>::notify_one and atomic<T>::notify_all,
|
||
|
||
- [(3.2)](#wait-3.2)
|
||
|
||
atomic_flag::notify_one and atomic_flag::notify_all,
|
||
|
||
- [(3.3)](#wait-3.3)
|
||
|
||
atomic_notify_one and atomic_notify_all,
|
||
|
||
- [(3.4)](#wait-3.4)
|
||
|
||
atomic_flag_notify_one and atomic_flag_notify_all, and
|
||
|
||
- [(3.5)](#wait-3.5)
|
||
|
||
atomic_ref<T>::notify_one and atomic_ref<T>::notify_all[.](#wait-3.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[4](#wait-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3182)
|
||
|
||
A call to an atomic waiting operation on an atomic object M is [*eligible to be unblocked*](#def:eligible_to_be_unblocked "32.5.6 Waiting and notifying [atomics.wait]") by a call to an atomic notifying operation on M if there exist side effects X and Y on M such that:
|
||
|
||
- [(4.1)](#wait-4.1)
|
||
|
||
the atomic waiting operation has blocked after observing the result of X,
|
||
|
||
- [(4.2)](#wait-4.2)
|
||
|
||
X precedes Y in the modification order of M, and
|
||
|
||
- [(4.3)](#wait-4.3)
|
||
|
||
Y happens before the call to the atomic notifying operation[.](#wait-4.sentence-1)
|
||
|
||
### [32.5.7](#ref.generic) Class template atomic_ref [[atomics.ref.generic]](atomics.ref.generic)
|
||
|
||
#### [32.5.7.1](#ref.generic.general) General [[atomics.ref.generic.general]](atomics.ref.generic.general)
|
||
|
||
[ð](#lib:atomic_ref)
|
||
|
||
namespace std {template<class T> struct atomic_ref {private: T* ptr; // *exposition only*public:using value_type = remove_cv_t<T>; static constexpr size_t required_alignment = *implementation-defined*; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const noexcept; constexpr explicit atomic_ref(T&); constexpr atomic_ref(const atomic_ref&) noexcept;
|
||
atomic_ref& operator=(const atomic_ref&) = delete; constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr value_type operator=(value_type) const noexcept; constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept; constexpr operator value_type() const noexcept; constexpr value_type exchange(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_weak(value_type&, value_type,
|
||
memory_order, memory_order) const noexcept; constexpr bool compare_exchange_strong(value_type&, value_type,
|
||
memory_order, memory_order) const noexcept; constexpr bool compare_exchange_weak(value_type&, value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_strong(value_type&, value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void notify_one() const noexcept; constexpr void notify_all() const noexcept; constexpr T* address() const noexcept; };}
|
||
|
||
[1](#ref.generic.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3240)
|
||
|
||
An atomic_ref object applies atomic operations ([[atomics.general]](#general "32.5.1 General")) to
|
||
the object referenced by *ptr such that,
|
||
for the lifetime ([[basic.life]](basic.life "6.8.4 Lifetime")) of the atomic_ref object,
|
||
the object referenced by *ptr is an atomic object ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#ref.generic.general-1.sentence-1)
|
||
|
||
[2](#ref.generic.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3246)
|
||
|
||
The program is ill-formed if is_trivially_copyable_v<T> is false[.](#ref.generic.general-2.sentence-1)
|
||
|
||
[3](#ref.generic.general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3249)
|
||
|
||
The lifetime ([[basic.life]](basic.life "6.8.4 Lifetime")) of an object referenced by *ptr shall exceed the lifetime of all atomic_refs that reference the object[.](#ref.generic.general-3.sentence-1)
|
||
|
||
While any atomic_ref instances exist
|
||
that reference the *ptr object,
|
||
all accesses to that object shall exclusively occur
|
||
through those atomic_ref instances[.](#ref.generic.general-3.sentence-2)
|
||
|
||
No subobject of the object referenced by atomic_ref shall be concurrently referenced by any other atomic_ref object[.](#ref.generic.general-3.sentence-3)
|
||
|
||
[4](#ref.generic.general-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3259)
|
||
|
||
Atomic operations applied to an object
|
||
through a referencing atomic_ref are atomic with respect to
|
||
atomic operations applied through any other atomic_ref referencing the same object[.](#ref.generic.general-4.sentence-1)
|
||
|
||
[*Note [1](#ref.generic.general-note-1)*:
|
||
|
||
Atomic operations or the atomic_ref constructor can acquire
|
||
a shared resource, such as a lock associated with the referenced object,
|
||
to enable atomic operations to be applied to the referenced object[.](#ref.generic.general-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[5](#ref.generic.general-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3270)
|
||
|
||
The program is ill-formed
|
||
if is_always_lock_free is false andis_volatile_v<T> is true[.](#ref.generic.general-5.sentence-1)
|
||
|
||
#### [32.5.7.2](#ref.ops) Operations [[atomics.ref.ops]](atomics.ref.ops)
|
||
|
||
[ð](#lib:required_alignment,atomic_ref)
|
||
|
||
`static constexpr size_t required_alignment;
|
||
`
|
||
|
||
[1](#ref.ops-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3286)
|
||
|
||
The alignment required for an object to be referenced by an atomic reference,
|
||
which is at least alignof(T)[.](#ref.ops-1.sentence-1)
|
||
|
||
[2](#ref.ops-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3290)
|
||
|
||
[*Note [1](#ref.ops-note-1)*:
|
||
|
||
Hardware could require an object
|
||
referenced by an atomic_ref to have stricter alignment ([[basic.align]](basic.align "6.8.3 Alignment"))
|
||
than other objects of type T[.](#ref.ops-2.sentence-1)
|
||
|
||
Further, whether operations on an atomic_ref are lock-free could depend on the alignment of the referenced object[.](#ref.ops-2.sentence-2)
|
||
|
||
For example, lock-free operations on std::complex<double> could be supported only if aligned to 2*alignof(double)[.](#ref.ops-2.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:is_always_lock_free,atomic_ref)
|
||
|
||
`static constexpr bool is_always_lock_free;
|
||
`
|
||
|
||
[3](#ref.ops-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3312)
|
||
|
||
The static data member is_always_lock_free is true if the atomic_ref type's operations are always lock-free,
|
||
and false otherwise[.](#ref.ops-3.sentence-1)
|
||
|
||
[ð](#lib:is_lock_free,atomic_ref)
|
||
|
||
`bool is_lock_free() const noexcept;
|
||
`
|
||
|
||
[4](#ref.ops-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3327)
|
||
|
||
*Returns*: true if operations on all objects of the type atomic_ref<T> are lock-free,false otherwise[.](#ref.ops-4.sentence-1)
|
||
|
||
[ð](#lib:atomic_ref,constructor)
|
||
|
||
`constexpr atomic_ref(T& obj);
|
||
`
|
||
|
||
[5](#ref.ops-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3343)
|
||
|
||
*Preconditions*: The referenced object is aligned to required_alignment[.](#ref.ops-5.sentence-1)
|
||
|
||
[6](#ref.ops-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3347)
|
||
|
||
*Postconditions*: *this references obj[.](#ref.ops-6.sentence-1)
|
||
|
||
[7](#ref.ops-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3351)
|
||
|
||
*Throws*: Nothing[.](#ref.ops-7.sentence-1)
|
||
|
||
[ð](#lib:atomic_ref,constructor_)
|
||
|
||
`constexpr atomic_ref(const atomic_ref& ref) noexcept;
|
||
`
|
||
|
||
[8](#ref.ops-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3365)
|
||
|
||
*Postconditions*: *this references the object referenced by ref[.](#ref.ops-8.sentence-1)
|
||
|
||
[ð](#lib:store,atomic_ref)
|
||
|
||
`constexpr void store(value_type desired,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[9](#ref.ops-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3380)
|
||
|
||
*Constraints*: is_const_v<T> is false[.](#ref.ops-9.sentence-1)
|
||
|
||
[10](#ref.ops-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3384)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#ref.ops-10.sentence-1)
|
||
|
||
[11](#ref.ops-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3391)
|
||
|
||
*Effects*: Atomically replaces the value referenced by *ptr with the value of desired[.](#ref.ops-11.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#ref.ops-11.sentence-2)
|
||
|
||
[ð](#lib:operator=,atomic_ref)
|
||
|
||
`constexpr value_type operator=(value_type desired) const noexcept;
|
||
`
|
||
|
||
[12](#ref.ops-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3407)
|
||
|
||
*Constraints*: is_const_v<T> is false[.](#ref.ops-12.sentence-1)
|
||
|
||
[13](#ref.ops-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3411)
|
||
|
||
*Effects*: Equivalent to:store(desired);return desired;
|
||
|
||
[ð](#lib:load,atomic_ref)
|
||
|
||
`constexpr value_type load(memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[14](#ref.ops-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3429)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#ref.ops-14.sentence-1)
|
||
|
||
[15](#ref.ops-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3436)
|
||
|
||
*Effects*: Memory is affected according to the value of order[.](#ref.ops-15.sentence-1)
|
||
|
||
[16](#ref.ops-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3440)
|
||
|
||
*Returns*: Atomically returns the value referenced by *ptr[.](#ref.ops-16.sentence-1)
|
||
|
||
[ð](#lib:operator_type,atomic_ref)
|
||
|
||
`constexpr operator value_type() const noexcept;
|
||
`
|
||
|
||
[17](#ref.ops-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3454)
|
||
|
||
*Effects*: Equivalent to: return load();
|
||
|
||
[ð](#lib:exchange,atomic_ref)
|
||
|
||
`constexpr value_type exchange(value_type desired,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[18](#ref.ops-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3469)
|
||
|
||
*Constraints*: is_const_v<T> is false[.](#ref.ops-18.sentence-1)
|
||
|
||
[19](#ref.ops-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3473)
|
||
|
||
*Effects*: Atomically replaces the value referenced by *ptr with desired[.](#ref.ops-19.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#ref.ops-19.sentence-2)
|
||
|
||
This operation is an atomic read-modify-write operation ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#ref.ops-19.sentence-3)
|
||
|
||
[20](#ref.ops-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3480)
|
||
|
||
*Returns*: Atomically returns the value referenced by *ptr immediately before the effects[.](#ref.ops-20.sentence-1)
|
||
|
||
[ð](#lib:compare_exchange_weak,atomic_ref)
|
||
|
||
`constexpr bool compare_exchange_weak(value_type& expected, value_type desired,
|
||
memory_order success, memory_order failure) const noexcept;
|
||
|
||
constexpr bool compare_exchange_strong(value_type& expected, value_type desired,
|
||
memory_order success, memory_order failure) const noexcept;
|
||
|
||
constexpr bool compare_exchange_weak(value_type& expected, value_type desired,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
|
||
constexpr bool compare_exchange_strong(value_type& expected, value_type desired,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[21](#ref.ops-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3509)
|
||
|
||
*Constraints*: is_const_v<T> is false[.](#ref.ops-21.sentence-1)
|
||
|
||
[22](#ref.ops-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3513)
|
||
|
||
*Preconditions*: failure ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#ref.ops-22.sentence-1)
|
||
|
||
[23](#ref.ops-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3520)
|
||
|
||
*Effects*: Retrieves the value in expected[.](#ref.ops-23.sentence-1)
|
||
|
||
It then atomically compares the value representation of
|
||
the value referenced by *ptr for equality
|
||
with that previously retrieved from expected,
|
||
and if true, replaces the value referenced by *ptr with that in desired[.](#ref.ops-23.sentence-2)
|
||
|
||
If and only if the comparison is true,
|
||
memory is affected according to the value of success, and
|
||
if the comparison is false,
|
||
memory is affected according to the value of failure[.](#ref.ops-23.sentence-3)
|
||
|
||
When only one memory_order argument is supplied,
|
||
the value of success is order, and
|
||
the value of failure is order except that a value of memory_order::acq_rel shall be replaced by
|
||
the value memory_order::acquire and
|
||
a value of memory_order::release shall be replaced by
|
||
the value memory_order::relaxed[.](#ref.ops-23.sentence-4)
|
||
|
||
If and only if the comparison is false then,
|
||
after the atomic operation,
|
||
the value in expected is replaced by
|
||
the value read from the value referenced by *ptr during the atomic comparison[.](#ref.ops-23.sentence-5)
|
||
|
||
If the operation returns true,
|
||
these operations are atomic read-modify-write operations ([[intro.races]](intro.races "6.10.2.2 Data races"))
|
||
on the value referenced by *ptr[.](#ref.ops-23.sentence-6)
|
||
|
||
Otherwise, these operations are atomic load operations on that memory[.](#ref.ops-23.sentence-7)
|
||
|
||
[24](#ref.ops-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3549)
|
||
|
||
*Returns*: The result of the comparison[.](#ref.ops-24.sentence-1)
|
||
|
||
[25](#ref.ops-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3553)
|
||
|
||
*Remarks*: A weak compare-and-exchange operation may fail spuriously[.](#ref.ops-25.sentence-1)
|
||
|
||
That is, even when the contents of memory referred to
|
||
by expected and ptr are equal,
|
||
it may return false and
|
||
store back to expected the same memory contents
|
||
that were originally there[.](#ref.ops-25.sentence-2)
|
||
|
||
[*Note [2](#ref.ops-note-2)*:
|
||
|
||
This spurious failure enables implementation of compare-and-exchange
|
||
on a broader class of machines, e.g., load-locked store-conditional machines[.](#ref.ops-25.sentence-3)
|
||
|
||
A consequence of spurious failure is
|
||
that nearly all uses of weak compare-and-exchange will be in a loop[.](#ref.ops-25.sentence-4)
|
||
|
||
When a compare-and-exchange is in a loop,
|
||
the weak version will yield better performance on some platforms[.](#ref.ops-25.sentence-5)
|
||
|
||
When a weak compare-and-exchange would require a loop and
|
||
a strong one would not, the strong one is preferable[.](#ref.ops-25.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:wait,atomic_ref%3cT%3e)
|
||
|
||
`constexpr void wait(value_type old, memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[26](#ref.ops-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3579)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#ref.ops-26.sentence-1)
|
||
|
||
[27](#ref.ops-27)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3586)
|
||
|
||
*Effects*: Repeatedly performs the following steps, in order:
|
||
|
||
- [(27.1)](#ref.ops-27.1)
|
||
|
||
Evaluates load(order) and
|
||
compares its value representation for equality against that of old[.](#ref.ops-27.1.sentence-1)
|
||
|
||
- [(27.2)](#ref.ops-27.2)
|
||
|
||
If they compare unequal, returns[.](#ref.ops-27.2.sentence-1)
|
||
|
||
- [(27.3)](#ref.ops-27.3)
|
||
|
||
Blocks until it
|
||
is unblocked by an atomic notifying operation or is unblocked spuriously[.](#ref.ops-27.3.sentence-1)
|
||
|
||
[28](#ref.ops-28)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3600)
|
||
|
||
*Remarks*: This function is an atomic waiting operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))
|
||
on atomic object *ptr[.](#ref.ops-28.sentence-1)
|
||
|
||
[ð](#lib:notify_one,atomic_ref%3cT%3e)
|
||
|
||
`constexpr void notify_one() const noexcept;
|
||
`
|
||
|
||
[29](#ref.ops-29)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3612)
|
||
|
||
*Constraints*: is_const_v<T> is false[.](#ref.ops-29.sentence-1)
|
||
|
||
[30](#ref.ops-30)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3616)
|
||
|
||
*Effects*: Unblocks the execution of at least one atomic waiting operation on *ptr that is eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call,
|
||
if any such atomic waiting operations exist[.](#ref.ops-30.sentence-1)
|
||
|
||
[31](#ref.ops-31)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3622)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))
|
||
on atomic object *ptr[.](#ref.ops-31.sentence-1)
|
||
|
||
[ð](#lib:notify_all,atomic_ref%3cT%3e)
|
||
|
||
`constexpr void notify_all() const noexcept;
|
||
`
|
||
|
||
[32](#ref.ops-32)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3634)
|
||
|
||
*Constraints*: is_const_v<T> is false[.](#ref.ops-32.sentence-1)
|
||
|
||
[33](#ref.ops-33)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3638)
|
||
|
||
*Effects*: Unblocks the execution of all atomic waiting operations on *ptr that are eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call[.](#ref.ops-33.sentence-1)
|
||
|
||
[34](#ref.ops-34)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3643)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))
|
||
on atomic object *ptr[.](#ref.ops-34.sentence-1)
|
||
|
||
[ð](#lib:address,atomic_ref%3cT%3e)
|
||
|
||
`constexpr T* address() const noexcept;
|
||
`
|
||
|
||
[35](#ref.ops-35)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3655)
|
||
|
||
*Returns*: ptr[.](#ref.ops-35.sentence-1)
|
||
|
||
#### [32.5.7.3](#ref.int) Specializations for integral types [[atomics.ref.int]](atomics.ref.int)
|
||
|
||
[1](#ref.int-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3662)
|
||
|
||
There are specializations of the atomic_ref class template
|
||
for all integral types except cv bool[.](#ref.int-1.sentence-1)
|
||
|
||
For each such type *integral-type*,
|
||
the specialization atomic_ref<*integral-type*> provides
|
||
additional atomic operations appropriate to integral types[.](#ref.int-1.sentence-2)
|
||
|
||
[*Note [1](#ref.int-note-1)*:
|
||
|
||
The specialization atomic_ref<bool> uses the primary template ([[atomics.ref.generic]](#ref.generic "32.5.7 Class template atomic_ref"))[.](#ref.int-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#ref.int-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3674)
|
||
|
||
The program is ill-formed
|
||
if is_always_lock_free is false andis_volatile_v<*integral-type*> is true[.](#ref.int-2.sentence-1)
|
||
|
||
namespace std {template<> struct atomic_ref<*integral-type*> {private:*integral-type** ptr; // *exposition only*public:using value_type = remove_cv_t<*integral-type*>; using difference_type = value_type; static constexpr size_t required_alignment = *implementation-defined*; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const noexcept; constexpr explicit atomic_ref(*integral-type*&); constexpr atomic_ref(const atomic_ref&) noexcept;
|
||
atomic_ref& operator=(const atomic_ref&) = delete; constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr value_type operator=(value_type) const noexcept; constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept; constexpr operator value_type() const noexcept; constexpr value_type exchange(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_weak(value_type&, value_type,
|
||
memory_order, memory_order) const noexcept; constexpr bool compare_exchange_strong(value_type&, value_type,
|
||
memory_order, memory_order) const noexcept; constexpr bool compare_exchange_weak(value_type&, value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_strong(value_type&, value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_add(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_sub(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_and(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_or(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_xor(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_max(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_min(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_add(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_sub(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_and(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_or(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_xor(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_max(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_min(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type operator++(int) const noexcept; constexpr value_type operator--(int) const noexcept; constexpr value_type operator++() const noexcept; constexpr value_type operator--() const noexcept; constexpr value_type operator+=(value_type) const noexcept; constexpr value_type operator-=(value_type) const noexcept; constexpr value_type operator&=(value_type) const noexcept; constexpr value_type operator|=(value_type) const noexcept; constexpr value_type operator^=(value_type) const noexcept; constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void notify_one() const noexcept; constexpr void notify_all() const noexcept; constexpr *integral-type** address() const noexcept; };}
|
||
|
||
[3](#ref.int-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3761)
|
||
|
||
Descriptions are provided below only for members
|
||
that differ from the primary template[.](#ref.int-3.sentence-1)
|
||
|
||
[4](#ref.int-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3765)
|
||
|
||
The following operations perform arithmetic computations[.](#ref.int-4.sentence-1)
|
||
|
||
The correspondence among key, operator, and computation is specified
|
||
in Table [155](#tab:atomic.types.int.comp "Table 155: Atomic arithmetic computations")[.](#ref.int-4.sentence-2)
|
||
|
||
[ð](#lib:fetch_add,atomic_ref%3cintegral-type%3e)
|
||
|
||
`constexpr value_type fetch_key(value_type operand,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[5](#ref.int-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3783)
|
||
|
||
*Constraints*: is_const_v<*integral-type*> is false[.](#ref.int-5.sentence-1)
|
||
|
||
[6](#ref.int-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3787)
|
||
|
||
*Effects*: Atomically replaces the value referenced by *ptr with
|
||
the result of the computation applied to the value referenced by *ptr and the given operand[.](#ref.int-6.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#ref.int-6.sentence-2)
|
||
|
||
These operations are atomic read-modify-write operations ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#ref.int-6.sentence-3)
|
||
|
||
[7](#ref.int-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3795)
|
||
|
||
*Returns*: Atomically, the value referenced by *ptr immediately before the effects[.](#ref.int-7.sentence-1)
|
||
|
||
[8](#ref.int-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3800)
|
||
|
||
*Remarks*: Except for fetch_max and fetch_min, for signed integer types
|
||
the result is as if the object value and parameters
|
||
were converted to their corresponding unsigned types,
|
||
the computation performed on those types, and
|
||
the result converted back to the signed type[.](#ref.int-8.sentence-1)
|
||
|
||
[*Note [2](#ref.int-note-2)*:
|
||
|
||
There are no undefined results arising from the computation[.](#ref.int-8.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[9](#ref.int-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3812)
|
||
|
||
For fetch_max and fetch_min, the maximum and minimum
|
||
computation is performed as if by max and min algorithms ([[alg.min.max]](alg.min.max "26.8.9 Minimum and maximum")), respectively,
|
||
with the object value and the first parameter as the arguments[.](#ref.int-9.sentence-1)
|
||
|
||
[ð](#lib:store_add,atomic_ref%3cintegral-type%3e)
|
||
|
||
`constexpr void store_key(value_type operand,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[10](#ref.int-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3831)
|
||
|
||
*Preconditions*: order is memory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#ref.int-10.sentence-1)
|
||
|
||
[11](#ref.int-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3837)
|
||
|
||
*Effects*: Atomically replaces the value referenced by *ptr with the result of the computation applied to
|
||
the value referenced by *ptr and the given operand[.](#ref.int-11.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#ref.int-11.sentence-2)
|
||
|
||
These operations are atomic modify-write operations ([[atomics.order]](#order "32.5.4 Order and consistency"))[.](#ref.int-11.sentence-3)
|
||
|
||
[12](#ref.int-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3845)
|
||
|
||
*Remarks*: Except for store_max and store_min,
|
||
for signed integer types,
|
||
the result is as if *ptr and parameters
|
||
were converted to their corresponding unsigned types,
|
||
the computation performed on those types, and
|
||
the result converted back to the signed type[.](#ref.int-12.sentence-1)
|
||
|
||
[*Note [3](#ref.int-note-3)*:
|
||
|
||
There are no undefined results arising from the computation[.](#ref.int-12.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
For store_max and store_min,
|
||
the maximum and minimum computation is performed
|
||
as if by max and min algorithms ([[alg.min.max]](alg.min.max "26.8.9 Minimum and maximum")), respectively,
|
||
with *ptr and the first parameter as the arguments[.](#ref.int-12.sentence-3)
|
||
|
||
[ð](#lib:operator+=,atomic_ref%3cintegral-type%3e)
|
||
|
||
`constexpr value_type operator op=(value_type operand) const noexcept;
|
||
`
|
||
|
||
[13](#ref.int-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3872)
|
||
|
||
*Constraints*: is_const_v<*integral-type*> is false[.](#ref.int-13.sentence-1)
|
||
|
||
[14](#ref.int-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3876)
|
||
|
||
*Effects*: Equivalent to:return fetch_*key*(operand) *op* operand;
|
||
|
||
#### [32.5.7.4](#ref.float) Specializations for floating-point types [[atomics.ref.float]](atomics.ref.float)
|
||
|
||
[1](#ref.float-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3884)
|
||
|
||
There are specializations of the atomic_ref class template
|
||
for all floating-point types[.](#ref.float-1.sentence-1)
|
||
|
||
For each such type *floating-point-type*,
|
||
the specialization atomic_ref<*floating-point-type*> provides
|
||
additional atomic operations appropriate to floating-point types[.](#ref.float-1.sentence-2)
|
||
|
||
[2](#ref.float-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3892)
|
||
|
||
The program is ill-formed
|
||
if is_always_lock_free is false andis_volatile_v<*floating-point-type*> is true[.](#ref.float-2.sentence-1)
|
||
|
||
namespace std {template<> struct atomic_ref<*floating-point-type*> {private:*floating-point-type** ptr; // *exposition only*public:using value_type = remove_cv_t<*floating-point-type*>; using difference_type = value_type; static constexpr size_t required_alignment = *implementation-defined*; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const noexcept; constexpr explicit atomic_ref(*floating-point-type*&); constexpr atomic_ref(const atomic_ref&) noexcept;
|
||
atomic_ref& operator=(const atomic_ref&) = delete; constexpr void store(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type operator=(value_type) const noexcept; constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept; constexpr operator value_type() const noexcept; constexpr value_type exchange(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_weak(value_type&, value_type,
|
||
memory_order, memory_order) const noexcept; constexpr bool compare_exchange_strong(value_type&, value_type,
|
||
memory_order, memory_order) const noexcept; constexpr bool compare_exchange_weak(value_type&, value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_strong(value_type&, value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_add(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_sub(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_max(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_min(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_fmaximum(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_fminimum(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_fmaximum_num(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_fminimum_num(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_add(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void store_sub(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void store_max(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void store_min(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void store_fmaximum(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_fminimum(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_fmaximum_num(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_fminimum_num(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type operator+=(value_type) const noexcept; constexpr value_type operator-=(value_type) const noexcept; constexpr void wait(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void notify_one() const noexcept; constexpr void notify_all() const noexcept; constexpr *floating-point-type** address() const noexcept; };}
|
||
|
||
[3](#ref.float-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3975)
|
||
|
||
Descriptions are provided below only for members
|
||
that differ from the primary template[.](#ref.float-3.sentence-1)
|
||
|
||
[4](#ref.float-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L3979)
|
||
|
||
The following operations perform arithmetic computations[.](#ref.float-4.sentence-1)
|
||
|
||
The correspondence among key, operator, and computation is specified
|
||
in Table [155](#tab:atomic.types.int.comp "Table 155: Atomic arithmetic computations"),
|
||
except for the keysmax,min,fmaximum,fminimum,fmaximum_num, andfminimum_num,
|
||
which are specified below[.](#ref.float-4.sentence-2)
|
||
|
||
[ð](#lib:fetch_add,atomic_ref%3cfloating-point-type%3e)
|
||
|
||
`constexpr value_type fetch_key(value_type operand,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[5](#ref.float-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4006)
|
||
|
||
*Constraints*: is_const_v<*floating-point-type*> is false[.](#ref.float-5.sentence-1)
|
||
|
||
[6](#ref.float-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4010)
|
||
|
||
*Effects*: Atomically replaces the value referenced by *ptr with
|
||
the result of the computation applied to the value referenced by *ptr and the given operand[.](#ref.float-6.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#ref.float-6.sentence-2)
|
||
|
||
These operations are atomic read-modify-write operations ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#ref.float-6.sentence-3)
|
||
|
||
[7](#ref.float-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4018)
|
||
|
||
*Returns*: Atomically, the value referenced by *ptr immediately before the effects[.](#ref.float-7.sentence-1)
|
||
|
||
[8](#ref.float-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4023)
|
||
|
||
*Remarks*: If the result is not a representable value for its type ([[expr.pre]](expr.pre "7.1 Preamble")),
|
||
the result is unspecified,
|
||
but the operations otherwise have no undefined behavior[.](#ref.float-8.sentence-1)
|
||
|
||
Atomic arithmetic operations on *floating-point-type* should conform to
|
||
the std::numeric_limits<value_type> traits
|
||
associated with the floating-point type ([[limits.syn]](limits.syn "17.3.3 Header <limits> synopsis"))[.](#ref.float-8.sentence-2)
|
||
|
||
The floating-point environment ([[cfenv]](cfenv "29.3 The floating-point environment"))
|
||
for atomic arithmetic operations on *floating-point-type* may be different than the calling thread's floating-point environment[.](#ref.float-8.sentence-3)
|
||
|
||
[9](#ref.float-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4035)
|
||
|
||
- [(9.1)](#ref.float-9.1)
|
||
|
||
For fetch_fmaximum and fetch_fminimum,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum and fminimum, respectively,
|
||
with *ptr and the first parameter as the arguments[.](#ref.float-9.1.sentence-1)
|
||
|
||
- [(9.2)](#ref.float-9.2)
|
||
|
||
For fetch_fmaximum_num and fetch_fminimum_num,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum_num and fminimum_num, respectively,
|
||
with *ptr and the first parameter as the arguments[.](#ref.float-9.2.sentence-1)
|
||
|
||
- [(9.3)](#ref.float-9.3)
|
||
|
||
For fetch_max and fetch_min,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum_num and fminimum_num, respectively,
|
||
with *ptr and the first parameter as the arguments, except that:
|
||
* [(9.3.1)](#ref.float-9.3.1)
|
||
|
||
If both arguments are NaN, an unspecified NaN value is stored at *ptr[.](#ref.float-9.3.1.sentence-1)
|
||
|
||
* [(9.3.2)](#ref.float-9.3.2)
|
||
|
||
If exactly one argument is a NaN,
|
||
either the other argument or an unspecified NaN value is stored at *ptr;
|
||
it is unspecified which[.](#ref.float-9.3.2.sentence-1)
|
||
|
||
* [(9.3.3)](#ref.float-9.3.3)
|
||
|
||
If the arguments are differently signed zeros,
|
||
which of these values is stored at *ptr is unspecified[.](#ref.float-9.3.3.sentence-1)
|
||
|
||
[10](#ref.float-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4065)
|
||
|
||
*Recommended practice*: The implementation of fetch_max and fetch_min should treat negative zero as smaller than positive zero[.](#ref.float-10.sentence-1)
|
||
|
||
[ð](#lib:store_add,atomic_ref%3cfloating-point-type%3e)
|
||
|
||
`constexpr void store_key(value_type operand,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[11](#ref.float-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4085)
|
||
|
||
*Preconditions*: order is memory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#ref.float-11.sentence-1)
|
||
|
||
[12](#ref.float-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4091)
|
||
|
||
*Effects*: Atomically replaces the value referenced by *ptr with the result of the computation applied to
|
||
the value referenced by *ptr and the given operand[.](#ref.float-12.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#ref.float-12.sentence-2)
|
||
|
||
These operations are atomic modify-write operations ([[atomics.order]](#order "32.5.4 Order and consistency"))[.](#ref.float-12.sentence-3)
|
||
|
||
[13](#ref.float-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4099)
|
||
|
||
*Remarks*: If the result is not a representable value for its type ([[expr.pre]](expr.pre "7.1 Preamble")),
|
||
the result is unspecified,
|
||
but the operations otherwise have no undefined behavior[.](#ref.float-13.sentence-1)
|
||
|
||
Atomic arithmetic operations on *floating-point-type* should conform to the numeric_limits<*floating-point-type*> traits associated with the floating-point type ([[limits.syn]](limits.syn "17.3.3 Header <limits> synopsis"))[.](#ref.float-13.sentence-2)
|
||
|
||
The floating-point environment ([[cfenv]](cfenv "29.3 The floating-point environment"))
|
||
for atomic arithmetic operations on *floating-point-type* may be different than the calling thread's floating-point environment[.](#ref.float-13.sentence-3)
|
||
|
||
The arithmetic rules of floating-point atomic modify-write operations
|
||
may be different from operations on floating-point types or
|
||
atomic floating-point types[.](#ref.float-13.sentence-4)
|
||
|
||
[*Note [1](#ref.float-note-1)*:
|
||
|
||
Tree reductions are permitted for atomic modify-write operations[.](#ref.float-13.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[14](#ref.float-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4117)
|
||
|
||
- [(14.1)](#ref.float-14.1)
|
||
|
||
For store_fmaximum and store_fminimum,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum and fminimum, respectively,
|
||
with *ptr and the first parameter as the arguments[.](#ref.float-14.1.sentence-1)
|
||
|
||
- [(14.2)](#ref.float-14.2)
|
||
|
||
For store_fmaximum_num and store_fminimum_num,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum_num and fminimum_num, respectively,
|
||
with *ptr and the first parameter as the arguments[.](#ref.float-14.2.sentence-1)
|
||
|
||
- [(14.3)](#ref.float-14.3)
|
||
|
||
For store_max and store_min,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum_num and fminimum_num, respectively,
|
||
with *ptr and the first parameter as the arguments, except that:
|
||
* [(14.3.1)](#ref.float-14.3.1)
|
||
|
||
If both arguments are NaN, an unspecified NaN value is stored at *ptr[.](#ref.float-14.3.1.sentence-1)
|
||
|
||
* [(14.3.2)](#ref.float-14.3.2)
|
||
|
||
If exactly one argument is a NaN,
|
||
either the other argument or an unspecified NaN value is stored at *ptr,
|
||
it is unspecified which[.](#ref.float-14.3.2.sentence-1)
|
||
|
||
* [(14.3.3)](#ref.float-14.3.3)
|
||
|
||
If the arguments are differently signed zeros,
|
||
which of these values is stored at *ptr is unspecified[.](#ref.float-14.3.3.sentence-1)
|
||
|
||
[15](#ref.float-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4147)
|
||
|
||
*Recommended practice*: The implementation of store_max and store_min should treat negative zero as smaller than positive zero[.](#ref.float-15.sentence-1)
|
||
|
||
[ð](#lib:operator+=,atomic_ref%3cfloating-point-type%3e)
|
||
|
||
`constexpr value_type operator op=(value_type operand) const noexcept;
|
||
`
|
||
|
||
[16](#ref.float-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4160)
|
||
|
||
*Constraints*: is_const_v<*floating-point-type*> is false[.](#ref.float-16.sentence-1)
|
||
|
||
[17](#ref.float-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4164)
|
||
|
||
*Effects*: Equivalent to:return fetch_*key*(operand) *op* operand;
|
||
|
||
#### [32.5.7.5](#ref.pointer) Specialization for pointers [[atomics.ref.pointer]](atomics.ref.pointer)
|
||
|
||
[1](#ref.pointer-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4173)
|
||
|
||
There are specializations of the atomic_ref class template
|
||
for all pointer-to-object types[.](#ref.pointer-1.sentence-1)
|
||
|
||
For each such type *pointer-type*,
|
||
the specialization atomic_ref<*pointer-type*> provides
|
||
additional atomic operations appropriate to pointer types[.](#ref.pointer-1.sentence-2)
|
||
|
||
[2](#ref.pointer-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4180)
|
||
|
||
The program is ill-formed
|
||
if is_always_lock_free is false andis_volatile_v<*pointer-type*> is true[.](#ref.pointer-2.sentence-1)
|
||
|
||
namespace std {template<> struct atomic_ref<*pointer-type*> {private:*pointer-type** ptr; // *exposition only*public:using value_type = remove_cv_t<*pointer-type*>; using difference_type = ptrdiff_t; static constexpr size_t required_alignment = *implementation-defined*; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const noexcept; constexpr explicit atomic_ref(*pointer-type*&); constexpr atomic_ref(const atomic_ref&) noexcept;
|
||
atomic_ref& operator=(const atomic_ref&) = delete; constexpr void store(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr value_type operator=(value_type) const noexcept; constexpr value_type load(memory_order = memory_order::seq_cst) const noexcept; constexpr operator value_type() const noexcept; constexpr value_type exchange(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_weak(value_type&, value_type,
|
||
memory_order, memory_order) const noexcept; constexpr bool compare_exchange_strong(value_type&, value_type,
|
||
memory_order, memory_order) const noexcept; constexpr bool compare_exchange_weak(value_type&, value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr bool compare_exchange_strong(value_type&, value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_add(difference_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_sub(difference_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_max(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type fetch_min(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_add(difference_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_sub(difference_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_max(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr void store_min(value_type,
|
||
memory_order = memory_order::seq_cst) const noexcept; constexpr value_type operator++(int) const noexcept; constexpr value_type operator--(int) const noexcept; constexpr value_type operator++() const noexcept; constexpr value_type operator--() const noexcept; constexpr value_type operator+=(difference_type) const noexcept; constexpr value_type operator-=(difference_type) const noexcept; constexpr void wait(value_type, memory_order = memory_order::seq_cst) const noexcept; constexpr void notify_one() const noexcept; constexpr void notify_all() const noexcept; constexpr *pointer-type** address() const noexcept; };}
|
||
|
||
[3](#ref.pointer-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4252)
|
||
|
||
Descriptions are provided below only for members
|
||
that differ from the primary template[.](#ref.pointer-3.sentence-1)
|
||
|
||
[4](#ref.pointer-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4256)
|
||
|
||
The following operations perform arithmetic computations[.](#ref.pointer-4.sentence-1)
|
||
|
||
The correspondence among key, operator, and computation is specified
|
||
in Table [156](#tab:atomic.types.pointer.comp "Table 156: Atomic pointer computations")[.](#ref.pointer-4.sentence-2)
|
||
|
||
[ð](#lib:fetch_add,atomic_ref%3cpointer-type%3e)
|
||
|
||
`constexpr value_type fetch_key(difference_type operand,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[5](#ref.pointer-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4271)
|
||
|
||
*Constraints*: is_const_v<*pointer-type*> is false[.](#ref.pointer-5.sentence-1)
|
||
|
||
[6](#ref.pointer-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4275)
|
||
|
||
*Mandates*: remove_pointer_t<*pointer-type*> is a complete object type[.](#ref.pointer-6.sentence-1)
|
||
|
||
[7](#ref.pointer-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4279)
|
||
|
||
*Effects*: Atomically replaces the value referenced by *ptr with
|
||
the result of the computation applied to the value referenced by *ptr and the given operand[.](#ref.pointer-7.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#ref.pointer-7.sentence-2)
|
||
|
||
These operations are atomic read-modify-write operations ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#ref.pointer-7.sentence-3)
|
||
|
||
[8](#ref.pointer-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4287)
|
||
|
||
*Returns*: Atomically, the value referenced by *ptr immediately before the effects[.](#ref.pointer-8.sentence-1)
|
||
|
||
[9](#ref.pointer-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4292)
|
||
|
||
*Remarks*: The result may be an undefined address,
|
||
but the operations otherwise have no undefined behavior[.](#ref.pointer-9.sentence-1)
|
||
|
||
[10](#ref.pointer-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4297)
|
||
|
||
For fetch_max and fetch_min, the maximum and minimum
|
||
computation is performed as if by max and min algorithms ([[alg.min.max]](alg.min.max "26.8.9 Minimum and maximum")), respectively, with the object value and the first
|
||
parameter as the arguments[.](#ref.pointer-10.sentence-1)
|
||
|
||
[*Note [1](#ref.pointer-note-1)*:
|
||
|
||
If the pointers point to different complete objects (or subobjects thereof),
|
||
the < operator does not establish a strict weak ordering
|
||
(Table [29](utility.arg.requirements#tab:cpp17.lessthancomparable "Table 29: Cpp17LessThanComparable requirements"), [[expr.rel]](expr.rel "7.6.9 Relational operators"))[.](#ref.pointer-10.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:store_add,atomic_ref%3cpointer-type%3e)
|
||
|
||
`constexpr void store_key(see above operand,
|
||
memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[11](#ref.pointer-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4320)
|
||
|
||
*Mandates*: T is a complete object type[.](#ref.pointer-11.sentence-1)
|
||
|
||
[12](#ref.pointer-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4324)
|
||
|
||
*Preconditions*: order is memory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#ref.pointer-12.sentence-1)
|
||
|
||
[13](#ref.pointer-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4330)
|
||
|
||
*Effects*: Atomically replaces the value referenced by *ptr with the result of the computation applied to
|
||
the value referenced by *ptr and the given operand[.](#ref.pointer-13.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#ref.pointer-13.sentence-2)
|
||
|
||
These operations are atomic modify-write operations ([[atomics.order]](#order "32.5.4 Order and consistency"))[.](#ref.pointer-13.sentence-3)
|
||
|
||
[14](#ref.pointer-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4338)
|
||
|
||
*Remarks*: The result may be an undefined address,
|
||
but the operations otherwise have no undefined behavior[.](#ref.pointer-14.sentence-1)
|
||
|
||
For store_max and store_min,
|
||
the maximum and minimum computation is performed
|
||
as if by max and min algorithms ([[alg.min.max]](alg.min.max "26.8.9 Minimum and maximum")), respectively,
|
||
with *ptr and the first parameter as the arguments[.](#ref.pointer-14.sentence-2)
|
||
|
||
[*Note [2](#ref.pointer-note-2)*:
|
||
|
||
If the pointers point to different complete objects (or subobjects thereof),
|
||
the < operator does not establish
|
||
a strict weak ordering (Table [29](utility.arg.requirements#tab:cpp17.lessthancomparable "Table 29: Cpp17LessThanComparable requirements"), [[expr.rel]](expr.rel "7.6.9 Relational operators"))[.](#ref.pointer-14.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:operator+=,atomic_ref%3cpointer-type%3e)
|
||
|
||
`constexpr value_type operator op=(difference_type operand) const noexcept;
|
||
`
|
||
|
||
[15](#ref.pointer-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4360)
|
||
|
||
*Constraints*: is_const_v<*pointer-type*> is false[.](#ref.pointer-15.sentence-1)
|
||
|
||
[16](#ref.pointer-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4364)
|
||
|
||
*Effects*: Equivalent to:return fetch_*key*(operand) *op* operand;
|
||
|
||
#### [32.5.7.6](#ref.memop) Member operators
|
||
common to integers and pointers to objects [[atomics.ref.memop]](atomics.ref.memop)
|
||
|
||
[1](#ref.memop-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4373)
|
||
|
||
Let *referred-type* be *pointer-type* for the specializations in [[atomics.ref.pointer]](#ref.pointer "32.5.7.5 Specialization for pointers") and
|
||
be *integral-type* for the specializations in [[atomics.ref.int]](#ref.int "32.5.7.3 Specializations for integral types")[.](#ref.memop-1.sentence-1)
|
||
|
||
[ð](#lib:operator++,atomic_ref%3cpointer-type%3e)
|
||
|
||
`constexpr value_type operator++(int) const noexcept;
|
||
`
|
||
|
||
[2](#ref.memop-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4388)
|
||
|
||
*Constraints*: is_const_v<*referred-type*> is false[.](#ref.memop-2.sentence-1)
|
||
|
||
[3](#ref.memop-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4392)
|
||
|
||
*Effects*: Equivalent to: return fetch_add(1);
|
||
|
||
[ð](#lib:operator--,atomic_ref%3cpointer-type%3e)
|
||
|
||
`constexpr value_type operator--(int) const noexcept;
|
||
`
|
||
|
||
[4](#ref.memop-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4404)
|
||
|
||
*Constraints*: is_const_v<*referred-type*> is false[.](#ref.memop-4.sentence-1)
|
||
|
||
[5](#ref.memop-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4408)
|
||
|
||
*Effects*: Equivalent to: return fetch_sub(1);
|
||
|
||
[ð](#lib:operator++,atomic_ref%3cpointer-type%3e_)
|
||
|
||
`constexpr value_type operator++() const noexcept;
|
||
`
|
||
|
||
[6](#ref.memop-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4420)
|
||
|
||
*Constraints*: is_const_v<*referred-type*> is false[.](#ref.memop-6.sentence-1)
|
||
|
||
[7](#ref.memop-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4424)
|
||
|
||
*Effects*: Equivalent to: return fetch_add(1) + 1;
|
||
|
||
[ð](#lib:operator--,atomic_ref%3cpointer-type%3e_)
|
||
|
||
`constexpr value_type operator--() const noexcept;
|
||
`
|
||
|
||
[8](#ref.memop-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4436)
|
||
|
||
*Constraints*: is_const_v<*referred-type*> is false[.](#ref.memop-8.sentence-1)
|
||
|
||
[9](#ref.memop-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4440)
|
||
|
||
*Effects*: Equivalent to: return fetch_sub(1) - 1;
|
||
|
||
### [32.5.8](#types.generic) Class template atomic [[atomics.types.generic]](atomics.types.generic)
|
||
|
||
#### [32.5.8.1](#types.generic.general) General [[atomics.types.generic.general]](atomics.types.generic.general)
|
||
|
||
[ð](#lib:atomic)
|
||
|
||
namespace std {template<class T> struct atomic {using value_type = T; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; // [[atomics.types.operations]](#types.operations "32.5.8.2 Operations on atomic types"), operations on atomic typesconstexpr atomic() noexcept(is_nothrow_default_constructible_v<T>); constexpr atomic(T) noexcept;
|
||
atomic(const atomic&) = delete;
|
||
atomic& operator=(const atomic&) = delete;
|
||
atomic& operator=(const atomic&) volatile = delete;
|
||
|
||
T load(memory_order = memory_order::seq_cst) const volatile noexcept; constexpr T load(memory_order = memory_order::seq_cst) const noexcept; operator T() const volatile noexcept; constexpr operator T() const noexcept; void store(T, memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store(T, memory_order = memory_order::seq_cst) noexcept;
|
||
T operator=(T) volatile noexcept; constexpr T operator=(T) noexcept;
|
||
|
||
T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept; constexpr T exchange(T, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(T&, T, memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_weak(T&, T, memory_order, memory_order) noexcept; bool compare_exchange_strong(T&, T, memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_strong(T&, T, memory_order, memory_order) noexcept; bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) noexcept; void wait(T, memory_order = memory_order::seq_cst) const volatile noexcept; constexpr void wait(T, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; constexpr void notify_one() noexcept; void notify_all() volatile noexcept; constexpr void notify_all() noexcept; };}
|
||
|
||
[1](#types.generic.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4498)
|
||
|
||
The template argument for T shall meet the[*Cpp17CopyConstructible*](utility.arg.requirements#:Cpp17CopyConstructible "16.4.4.2 Template argument requirements [utility.arg.requirements]") and [*Cpp17CopyAssignable*](utility.arg.requirements#:Cpp17CopyAssignable "16.4.4.2 Template argument requirements [utility.arg.requirements]") requirements[.](#types.generic.general-1.sentence-1)
|
||
|
||
The program is ill-formed if any of
|
||
|
||
- [(1.1)](#types.generic.general-1.1)
|
||
|
||
is_trivially_copyable_v<T>,
|
||
|
||
- [(1.2)](#types.generic.general-1.2)
|
||
|
||
is_copy_constructible_v<T>,
|
||
|
||
- [(1.3)](#types.generic.general-1.3)
|
||
|
||
is_move_constructible_v<T>,
|
||
|
||
- [(1.4)](#types.generic.general-1.4)
|
||
|
||
is_copy_assignable_v<T>,
|
||
|
||
- [(1.5)](#types.generic.general-1.5)
|
||
|
||
is_move_assignable_v<T>, or
|
||
|
||
- [(1.6)](#types.generic.general-1.6)
|
||
|
||
same_as<T, remove_cv_t<T>>,
|
||
|
||
is false[.](#types.generic.general-1.sentence-2)
|
||
|
||
[*Note [1](#types.generic.general-note-1)*:
|
||
|
||
Type arguments that are
|
||
not also statically initializable can be difficult to use[.](#types.generic.general-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#types.generic.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4516)
|
||
|
||
The specialization atomic<bool> is a standard-layout struct[.](#types.generic.general-2.sentence-1)
|
||
|
||
It has a trivial destructor[.](#types.generic.general-2.sentence-2)
|
||
|
||
[3](#types.generic.general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4520)
|
||
|
||
[*Note [2](#types.generic.general-note-2)*:
|
||
|
||
The representation of an atomic specialization
|
||
need not have the same size and alignment requirement as
|
||
its corresponding argument type[.](#types.generic.general-3.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
#### [32.5.8.2](#types.operations) Operations on atomic types [[atomics.types.operations]](atomics.types.operations)
|
||
|
||
[ð](#lib:atomic,constructor)
|
||
|
||
`constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
|
||
`
|
||
|
||
[1](#types.operations-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4538)
|
||
|
||
*Constraints*: is_default_constructible_v<T> is true[.](#types.operations-1.sentence-1)
|
||
|
||
[2](#types.operations-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4542)
|
||
|
||
*Effects*: Initializes the atomic object with the value of T()[.](#types.operations-2.sentence-1)
|
||
|
||
Initialization is not an atomic operation ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#types.operations-2.sentence-2)
|
||
|
||
[ð](#lib:atomic,constructor_)
|
||
|
||
`constexpr atomic(T desired) noexcept;
|
||
`
|
||
|
||
[3](#types.operations-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4557)
|
||
|
||
*Effects*: Initializes the object with the value desired[.](#types.operations-3.sentence-1)
|
||
|
||
Initialization is not an atomic operation ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#types.operations-3.sentence-2)
|
||
|
||
[*Note [1](#types.operations-note-1)*:
|
||
|
||
It is possible to have an access to an atomic object A race with its construction, for example by communicating the address of the
|
||
just-constructed object A to another thread viamemory_order::relaxed operations on a suitable atomic pointer
|
||
variable, and then immediately accessing A in the receiving thread[.](#types.operations-3.sentence-3)
|
||
|
||
This results in undefined behavior[.](#types.operations-3.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:is_always_lock_free,atomic)
|
||
|
||
`static constexpr bool is_always_lock_free = implementation-defined;
|
||
`
|
||
|
||
[4](#types.operations-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4582)
|
||
|
||
The static data member is_always_lock_free is true if the atomic type's operations are always lock-free, and false otherwise[.](#types.operations-4.sentence-1)
|
||
|
||
[*Note [2](#types.operations-note-2)*:
|
||
|
||
The value of is_always_lock_free is consistent with the value of
|
||
the corresponding ATOMIC_..._LOCK_FREE macro, if defined[.](#types.operations-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:atomic_is_lock_free)
|
||
|
||
`bool is_lock_free() const volatile noexcept;
|
||
bool is_lock_free() const noexcept;
|
||
`
|
||
|
||
[5](#types.operations-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4604)
|
||
|
||
*Returns*: true if the object's operations are lock-free, false otherwise[.](#types.operations-5.sentence-1)
|
||
|
||
[*Note [3](#types.operations-note-3)*:
|
||
|
||
The return value of the is_lock_free member function
|
||
is consistent with the value of is_always_lock_free for the same type[.](#types.operations-5.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:atomic_store)
|
||
|
||
`void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr void store(T desired, memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[6](#types.operations-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4625)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.operations-6.sentence-1)
|
||
|
||
[7](#types.operations-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4630)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#types.operations-7.sentence-1)
|
||
|
||
[8](#types.operations-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4637)
|
||
|
||
*Effects*: Atomically replaces the value pointed to by this with the value of desired[.](#types.operations-8.sentence-1)
|
||
|
||
Memory is affected according to the value oforder[.](#types.operations-8.sentence-2)
|
||
|
||
[ð](#lib:operator=,atomic)
|
||
|
||
`T operator=(T desired) volatile noexcept;
|
||
constexpr T operator=(T desired) noexcept;
|
||
`
|
||
|
||
[9](#types.operations-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4654)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.operations-9.sentence-1)
|
||
|
||
[10](#types.operations-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4659)
|
||
|
||
*Effects*: Equivalent to store(desired)[.](#types.operations-10.sentence-1)
|
||
|
||
[11](#types.operations-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4663)
|
||
|
||
*Returns*: desired[.](#types.operations-11.sentence-1)
|
||
|
||
[ð](#lib:atomic_load)
|
||
|
||
`T load(memory_order order = memory_order::seq_cst) const volatile noexcept;
|
||
constexpr T load(memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[12](#types.operations-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4680)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.operations-12.sentence-1)
|
||
|
||
[13](#types.operations-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4685)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#types.operations-13.sentence-1)
|
||
|
||
[14](#types.operations-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4692)
|
||
|
||
*Effects*: Memory is affected according to the value of order[.](#types.operations-14.sentence-1)
|
||
|
||
[15](#types.operations-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4696)
|
||
|
||
*Returns*: Atomically returns the value pointed to by this[.](#types.operations-15.sentence-1)
|
||
|
||
[ð](#lib:operator_type,atomic)
|
||
|
||
`operator T() const volatile noexcept;
|
||
constexpr operator T() const noexcept;
|
||
`
|
||
|
||
[16](#types.operations-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4711)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.operations-16.sentence-1)
|
||
|
||
[17](#types.operations-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4716)
|
||
|
||
*Effects*: Equivalent to: return load();
|
||
|
||
[ð](#lib:atomic_exchange)
|
||
|
||
`T exchange(T desired, memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr T exchange(T desired, memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[18](#types.operations-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4734)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.operations-18.sentence-1)
|
||
|
||
[19](#types.operations-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4739)
|
||
|
||
*Effects*: Atomically replaces the value pointed to by this with desired[.](#types.operations-19.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#types.operations-19.sentence-2)
|
||
|
||
These operations are atomic read-modify-write operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#types.operations-19.sentence-3)
|
||
|
||
[20](#types.operations-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4746)
|
||
|
||
*Returns*: Atomically returns the value pointed to by this immediately before the effects[.](#types.operations-20.sentence-1)
|
||
|
||
[ð](#lib:atomic_compare_exchange_weak)
|
||
|
||
`bool compare_exchange_weak(T& expected, T desired,
|
||
memory_order success, memory_order failure) volatile noexcept;
|
||
constexpr bool compare_exchange_weak(T& expected, T desired,
|
||
memory_order success, memory_order failure) noexcept;
|
||
bool compare_exchange_strong(T& expected, T desired,
|
||
memory_order success, memory_order failure) volatile noexcept;
|
||
constexpr bool compare_exchange_strong(T& expected, T desired,
|
||
memory_order success, memory_order failure) noexcept;
|
||
bool compare_exchange_weak(T& expected, T desired,
|
||
memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr bool compare_exchange_weak(T& expected, T desired,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
bool compare_exchange_strong(T& expected, T desired,
|
||
memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr bool compare_exchange_strong(T& expected, T desired,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[21](#types.operations-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4783)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.operations-21.sentence-1)
|
||
|
||
[22](#types.operations-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4788)
|
||
|
||
*Preconditions*: failure ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#types.operations-22.sentence-1)
|
||
|
||
[23](#types.operations-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4795)
|
||
|
||
*Effects*: Retrieves the value in expected[.](#types.operations-23.sentence-1)
|
||
|
||
It then atomically
|
||
compares the value representation of the value pointed to by this for equality with that previously retrieved from expected,
|
||
and if true, replaces the value pointed to
|
||
by this with that in desired[.](#types.operations-23.sentence-2)
|
||
|
||
If and only if the comparison is true, memory is affected according to the
|
||
value of success, and if the comparison is false, memory is affected according
|
||
to the value of failure[.](#types.operations-23.sentence-3)
|
||
|
||
When only one memory_order argument is
|
||
supplied, the value of success is order, and the value offailure is order except that a value of memory_order::acq_rel shall be replaced by the value memory_order::acquire and a value ofmemory_order::release shall be replaced by the valuememory_order::relaxed[.](#types.operations-23.sentence-4)
|
||
|
||
If and only if the comparison is false then, after the atomic operation,
|
||
the value in expected is replaced by the value
|
||
pointed to by this during the atomic comparison[.](#types.operations-23.sentence-5)
|
||
|
||
If the operation returns true, these
|
||
operations are atomic read-modify-write
|
||
operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races")) on the memory
|
||
pointed to by this[.](#types.operations-23.sentence-6)
|
||
|
||
Otherwise, these operations are atomic load operations on that memory[.](#types.operations-23.sentence-7)
|
||
|
||
[24](#types.operations-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4819)
|
||
|
||
*Returns*: The result of the comparison[.](#types.operations-24.sentence-1)
|
||
|
||
[25](#types.operations-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4823)
|
||
|
||
[*Note [4](#types.operations-note-4)*:
|
||
|
||
For example, the effect ofcompare_exchange_strong on objects without padding bits ([[basic.types.general]](basic.types.general#term.padding.bits "6.9.1 General")) isif (memcmp(this, &expected, sizeof(*this)) == 0) memcpy(this, &desired, sizeof(*this));else memcpy(&expected, this, sizeof(*this));
|
||
|
||
â *end note*]
|
||
|
||
[*Example [1](#types.operations-example-1)*:
|
||
|
||
The expected use of the compare-and-exchange operations is as follows[.](#types.operations-25.sentence-2)
|
||
|
||
The
|
||
compare-and-exchange operations will update expected when another iteration of
|
||
the loop is needed[.](#types.operations-25.sentence-3)
|
||
|
||
expected = current.load();do { desired = function(expected);} while (!current.compare_exchange_weak(expected, desired)); â *end example*]
|
||
|
||
[*Example [2](#types.operations-example-2)*:
|
||
|
||
Because the expected value is updated only on failure,
|
||
code releasing the memory containing the expected value on success will work[.](#types.operations-25.sentence-4)
|
||
|
||
For example, list head insertion will act atomically and would not introduce a
|
||
data race in the following code:do { p->next = head; // make new list node point to the current head} while (!head.compare_exchange_weak(p->next, p)); // try to insert
|
||
|
||
â *end example*]
|
||
|
||
[26](#types.operations-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4858)
|
||
|
||
Implementations should ensure that weak compare-and-exchange operations do not
|
||
consistently return false unless either the atomic object has value
|
||
different from expected or there are concurrent modifications to the
|
||
atomic object[.](#types.operations-26.sentence-1)
|
||
|
||
[27](#types.operations-27)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4864)
|
||
|
||
*Remarks*: A weak compare-and-exchange operation may fail spuriously[.](#types.operations-27.sentence-1)
|
||
|
||
That is, even when
|
||
the contents of memory referred to by expected and this are
|
||
equal, it may return false and store back to expected the same memory
|
||
contents that were originally there[.](#types.operations-27.sentence-2)
|
||
|
||
[*Note [5](#types.operations-note-5)*:
|
||
|
||
This
|
||
spurious failure enables implementation of compare-and-exchange on a broader class of
|
||
machines, e.g., load-locked store-conditional machines[.](#types.operations-27.sentence-3)
|
||
|
||
A
|
||
consequence of spurious failure is that nearly all uses of weak compare-and-exchange
|
||
will be in a loop[.](#types.operations-27.sentence-4)
|
||
|
||
When a compare-and-exchange is in a loop, the weak version will yield better performance
|
||
on some platforms[.](#types.operations-27.sentence-5)
|
||
|
||
When a weak compare-and-exchange would require a loop and a strong one
|
||
would not, the strong one is preferable[.](#types.operations-27.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
[28](#types.operations-28)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4881)
|
||
|
||
[*Note [6](#types.operations-note-6)*:
|
||
|
||
Under cases where the memcpy and memcmp semantics of the compare-and-exchange
|
||
operations apply, the comparisons can fail for values that compare equal withoperator== if the value representation has trap bits or alternate
|
||
representations of the same value[.](#types.operations-28.sentence-1)
|
||
|
||
Notably, on implementations conforming to
|
||
ISO/IEC 60559, floating-point -0.0 and +0.0 will not compare equal with memcmp but will compare equal with operator==,
|
||
and NaNs with the same payload will compare equal with memcmp but will not
|
||
compare equal with operator==[.](#types.operations-28.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[*Note [7](#types.operations-note-7)*:
|
||
|
||
Because compare-and-exchange acts on an object's value representation,
|
||
padding bits that never participate in the object's value representation
|
||
are ignored[.](#types.operations-28.sentence-3)
|
||
|
||
As a consequence, the following code is guaranteed to avoid
|
||
spurious failure:struct padded {char clank = 0x42; // Padding here.unsigned biff = 0xC0DEFEFE;};
|
||
atomic<padded> pad = {};
|
||
|
||
bool zap() { padded expected, desired{0, 0}; return pad.compare_exchange_strong(expected, desired);}
|
||
|
||
â *end note*]
|
||
|
||
[*Note [8](#types.operations-note-8)*:
|
||
|
||
For a union with bits that participate in the value representation
|
||
of some members but not others, compare-and-exchange might always fail[.](#types.operations-28.sentence-5)
|
||
|
||
This is because such padding bits have an indeterminate value when they
|
||
do not participate in the value representation of the active member[.](#types.operations-28.sentence-6)
|
||
|
||
As a consequence, the following code is not guaranteed to ever succeed:union pony {double celestia = 0.; short luna; // padded};
|
||
atomic<pony> princesses = {};
|
||
|
||
bool party(pony desired) { pony expected; return princesses.compare_exchange_strong(expected, desired);}
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:wait,atomic)
|
||
|
||
`void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept;
|
||
constexpr void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[29](#types.operations-29)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4942)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#types.operations-29.sentence-1)
|
||
|
||
[30](#types.operations-30)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4949)
|
||
|
||
*Effects*: Repeatedly performs the following steps, in order:
|
||
|
||
- [(30.1)](#types.operations-30.1)
|
||
|
||
Evaluates load(order) and
|
||
compares its value representation for equality against that of old[.](#types.operations-30.1.sentence-1)
|
||
|
||
- [(30.2)](#types.operations-30.2)
|
||
|
||
If they compare unequal, returns[.](#types.operations-30.2.sentence-1)
|
||
|
||
- [(30.3)](#types.operations-30.3)
|
||
|
||
Blocks until it
|
||
is unblocked by an atomic notifying operation or is unblocked spuriously[.](#types.operations-30.3.sentence-1)
|
||
|
||
[31](#types.operations-31)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4963)
|
||
|
||
*Remarks*: This function is an atomic waiting operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#types.operations-31.sentence-1)
|
||
|
||
[ð](#lib:notify_one,atomic)
|
||
|
||
`void notify_one() volatile noexcept;
|
||
constexpr void notify_one() noexcept;
|
||
`
|
||
|
||
[32](#types.operations-32)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4978)
|
||
|
||
*Effects*: Unblocks the execution of at least one atomic waiting operation
|
||
that is eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call,
|
||
if any such atomic waiting operations exist[.](#types.operations-32.sentence-1)
|
||
|
||
[33](#types.operations-33)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4984)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#types.operations-33.sentence-1)
|
||
|
||
[ð](#lib:notify_all,atomic)
|
||
|
||
`void notify_all() volatile noexcept;
|
||
constexpr void notify_all() noexcept;
|
||
`
|
||
|
||
[34](#types.operations-34)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L4999)
|
||
|
||
*Effects*: Unblocks the execution of all atomic waiting operations
|
||
that are eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call[.](#types.operations-34.sentence-1)
|
||
|
||
[35](#types.operations-35)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5004)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#types.operations-35.sentence-1)
|
||
|
||
#### [32.5.8.3](#types.int) Specializations for integers [[atomics.types.int]](atomics.types.int)
|
||
|
||
[1](#types.int-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5012)
|
||
|
||
There are specializations of the atomic class template for the integral typeschar,signed char,unsigned char,short,unsigned short,int,unsigned int,long,unsigned long,long long,unsigned long long,char8_t,char16_t,char32_t,wchar_t,
|
||
and any other types needed by the typedefs in the header [<cstdint>](cstdint.syn#header:%3ccstdint%3e "17.4.1 Header <cstdint> synopsis [cstdint.syn]")[.](#types.int-1.sentence-1)
|
||
|
||
For each such type *integral-type*, the specializationatomic<*integral-type*> provides additional atomic operations appropriate to integral types[.](#types.int-1.sentence-2)
|
||
|
||
[*Note [1](#types.int-note-1)*:
|
||
|
||
The specialization atomic<bool> uses the primary template ([[atomics.types.generic]](#types.generic "32.5.8 Class template atomic"))[.](#types.int-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
namespace std {template<> struct atomic<*integral-type*> {using value_type = *integral-type*; using difference_type = value_type; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; constexpr atomic() noexcept; constexpr atomic(*integral-type*) noexcept;
|
||
atomic(const atomic&) = delete;
|
||
atomic& operator=(const atomic&) = delete;
|
||
atomic& operator=(const atomic&) volatile = delete; void store(*integral-type*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store(*integral-type*, memory_order = memory_order::seq_cst) noexcept; *integral-type* operator=(*integral-type*) volatile noexcept; constexpr *integral-type* operator=(*integral-type*) noexcept; *integral-type* load(memory_order = memory_order::seq_cst) const volatile noexcept; constexpr *integral-type* load(memory_order = memory_order::seq_cst) const noexcept; operator *integral-type*() const volatile noexcept; constexpr operator *integral-type*() const noexcept; *integral-type* exchange(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *integral-type* exchange(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(*integral-type*&, *integral-type*,
|
||
memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_weak(*integral-type*&, *integral-type*,
|
||
memory_order, memory_order) noexcept; bool compare_exchange_strong(*integral-type*&, *integral-type*,
|
||
memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_strong(*integral-type*&, *integral-type*,
|
||
memory_order, memory_order) noexcept; bool compare_exchange_weak(*integral-type*&, *integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(*integral-type*&, *integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(*integral-type*&, *integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_strong(*integral-type*&, *integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *integral-type* fetch_add(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *integral-type* fetch_add(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *integral-type* fetch_sub(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *integral-type* fetch_sub(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *integral-type* fetch_and(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *integral-type* fetch_and(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *integral-type* fetch_or(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *integral-type* fetch_or(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *integral-type* fetch_xor(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *integral-type* fetch_xor(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *integral-type* fetch_max(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *integral-type* fetch_max(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *integral-type* fetch_min(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *integral-type* fetch_min(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_add(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_add(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_sub(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_sub(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_and(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_and(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_or(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_or(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_xor(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_xor(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_max(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_max(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_min(*integral-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_min(*integral-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *integral-type* operator++(int) volatile noexcept; constexpr *integral-type* operator++(int) noexcept; *integral-type* operator--(int) volatile noexcept; constexpr *integral-type* operator--(int) noexcept; *integral-type* operator++() volatile noexcept; constexpr *integral-type* operator++() noexcept; *integral-type* operator--() volatile noexcept; constexpr *integral-type* operator--() noexcept; *integral-type* operator+=(*integral-type*) volatile noexcept; constexpr *integral-type* operator+=(*integral-type*) noexcept; *integral-type* operator-=(*integral-type*) volatile noexcept; constexpr *integral-type* operator-=(*integral-type*) noexcept; *integral-type* operator&=(*integral-type*) volatile noexcept; constexpr *integral-type* operator&=(*integral-type*) noexcept; *integral-type* operator|=(*integral-type*) volatile noexcept; constexpr *integral-type* operator|=(*integral-type*) noexcept; *integral-type* operator^=(*integral-type*) volatile noexcept; constexpr *integral-type* operator^=(*integral-type*) noexcept; void wait(*integral-type*, memory_order = memory_order::seq_cst) const volatile noexcept; constexpr void wait(*integral-type*, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; constexpr void notify_one() noexcept; void notify_all() volatile noexcept; constexpr void notify_all() noexcept; };}
|
||
|
||
[2](#types.int-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5171)
|
||
|
||
The atomic integral specializations
|
||
are standard-layout structs[.](#types.int-2.sentence-1)
|
||
|
||
They each have
|
||
a trivial destructor[.](#types.int-2.sentence-2)
|
||
|
||
[3](#types.int-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5177)
|
||
|
||
Descriptions are provided below only for members that differ from the primary template[.](#types.int-3.sentence-1)
|
||
|
||
[4](#types.int-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5180)
|
||
|
||
The following operations perform arithmetic computations[.](#types.int-4.sentence-1)
|
||
|
||
The correspondence among key, operator, and computation is specified
|
||
in Table [155](#tab:atomic.types.int.comp "Table 155: Atomic arithmetic computations")[.](#types.int-4.sentence-2)
|
||
|
||
Table [155](#tab:atomic.types.int.comp) — Atomic arithmetic computations [[tab:atomic.types.int.comp]](./tab:atomic.types.int.comp)
|
||
|
||
| [ð](#tab:atomic.types.int.comp-row-1)<br>***key*** | **Op** | **Computation** | ***key*** | **Op** | **Computation** |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| [ð](#tab:atomic.types.int.comp-row-2)<br>add | + | addition | and | & | bitwise and |
|
||
| [ð](#tab:atomic.types.int.comp-row-3)<br>sub | - | subtraction | or | | | bitwise inclusive or |
|
||
| [ð](#tab:atomic.types.int.comp-row-4)<br>max | | maximum | xor | ^ | bitwise exclusive or |
|
||
| [ð](#tab:atomic.types.int.comp-row-5)<br>min | | minimum | | | |
|
||
|
||
[ð](#lib:atomic_fetch_add)
|
||
|
||
`integral-type fetch_key(integral-type operand,
|
||
memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr integral-type fetch_key(integral-type operand,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[5](#types.int-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5246)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.int-5.sentence-1)
|
||
|
||
[6](#types.int-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5251)
|
||
|
||
*Effects*: Atomically replaces the value pointed to bythis with the result of the computation applied to the
|
||
value pointed to by this and the given operand[.](#types.int-6.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#types.int-6.sentence-2)
|
||
|
||
These operations are atomic read-modify-write operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#types.int-6.sentence-3)
|
||
|
||
[7](#types.int-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5259)
|
||
|
||
*Returns*: Atomically, the value pointed to by this immediately before the effects[.](#types.int-7.sentence-1)
|
||
|
||
[8](#types.int-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5263)
|
||
|
||
*Remarks*: Except for fetch_max and fetch_min, for signed integer types
|
||
the result is as if the object value and parameters
|
||
were converted to their corresponding unsigned types,
|
||
the computation performed on those types, and
|
||
the result converted back to the signed type[.](#types.int-8.sentence-1)
|
||
|
||
[*Note [2](#types.int-note-2)*:
|
||
|
||
There are no undefined results arising from the computation[.](#types.int-8.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[9](#types.int-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5275)
|
||
|
||
For fetch_max and fetch_min, the maximum and minimum
|
||
computation is performed as if by max and min algorithms ([[alg.min.max]](alg.min.max "26.8.9 Minimum and maximum")), respectively,
|
||
with the object value and the first parameter as the arguments[.](#types.int-9.sentence-1)
|
||
|
||
[ð](#lib:atomic_store_add)
|
||
|
||
`void store_key(integral-type operand,
|
||
memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr void store_key(integral-type operand,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[10](#types.int-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5308)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.int-10.sentence-1)
|
||
|
||
[11](#types.int-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5313)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#types.int-11.sentence-1)
|
||
|
||
[12](#types.int-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5320)
|
||
|
||
*Effects*: Atomically replaces the value pointed to by this with the result of the computation applied to
|
||
the value pointed to by this and the given operand[.](#types.int-12.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#types.int-12.sentence-2)
|
||
|
||
These operations are atomic modify-write operations ([[atomics.order]](#order "32.5.4 Order and consistency"))[.](#types.int-12.sentence-3)
|
||
|
||
[13](#types.int-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5328)
|
||
|
||
*Remarks*: Except for store_max and store_min,
|
||
for signed integer types, the result is as if
|
||
the value pointed to by this and parameters
|
||
were converted to their corresponding unsigned types,
|
||
the computation performed on those types, and
|
||
the result converted back to the signed type[.](#types.int-13.sentence-1)
|
||
|
||
[*Note [3](#types.int-note-3)*:
|
||
|
||
There are no undefined results arising from the computation[.](#types.int-13.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
For store_max and store_min,
|
||
the maximum and minimum computation is performed
|
||
as if by max and min algorithms ([[alg.min.max]](alg.min.max "26.8.9 Minimum and maximum")), respectively,
|
||
with the value pointed to by this and the first parameter as the arguments[.](#types.int-13.sentence-3)
|
||
|
||
[ð](#lib:operator+=,atomic%3cT*%3e)
|
||
|
||
`integral-type operator op=(integral-type operand) volatile noexcept;
|
||
constexpr integral-type operator op=(integral-type operand) noexcept;
|
||
`
|
||
|
||
[14](#types.int-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5358)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.int-14.sentence-1)
|
||
|
||
[15](#types.int-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5363)
|
||
|
||
*Effects*: Equivalent to: return fetch_*key*(operand) *op* operand;
|
||
|
||
#### [32.5.8.4](#types.float) Specializations for floating-point types [[atomics.types.float]](atomics.types.float)
|
||
|
||
[1](#types.float-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5371)
|
||
|
||
There are specializations of the atomic class template for all cv-unqualified floating-point types[.](#types.float-1.sentence-1)
|
||
|
||
For each such type *floating-point-type*,
|
||
the specialization atomic<*floating-point-type*> provides additional atomic operations appropriate to floating-point types[.](#types.float-1.sentence-2)
|
||
|
||
namespace std {template<> struct atomic<*floating-point-type*> {using value_type = *floating-point-type*; using difference_type = value_type; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; constexpr atomic() noexcept; constexpr atomic(*floating-point-type*) noexcept;
|
||
atomic(const atomic&) = delete;
|
||
atomic& operator=(const atomic&) = delete;
|
||
atomic& operator=(const atomic&) volatile = delete; void store(*floating-point-type*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store(*floating-point-type*, memory_order = memory_order::seq_cst) noexcept; *floating-point-type* operator=(*floating-point-type*) volatile noexcept; constexpr *floating-point-type* operator=(*floating-point-type*) noexcept; *floating-point-type* load(memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* load(memory_order = memory_order::seq_cst) noexcept; operator *floating-point-type*() volatile noexcept; constexpr operator *floating-point-type*() noexcept; *floating-point-type* exchange(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* exchange(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(*floating-point-type*&, *floating-point-type*,
|
||
memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_weak(*floating-point-type*&, *floating-point-type*,
|
||
memory_order, memory_order) noexcept; bool compare_exchange_strong(*floating-point-type*&, *floating-point-type*,
|
||
memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_strong(*floating-point-type*&, *floating-point-type*,
|
||
memory_order, memory_order) noexcept; bool compare_exchange_weak(*floating-point-type*&, *floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(*floating-point-type*&, *floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(*floating-point-type*&, *floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_strong(*floating-point-type*&, *floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* fetch_add(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* fetch_add(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* fetch_sub(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* fetch_sub(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* fetch_max(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* fetch_max(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* fetch_min(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-poin-type*t fetch_min(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* fetch_fmaximum(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* fetch_fmaximum(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* fetch_fminimum(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* fetch_fminimum(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* fetch_fmaximum_num(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* fetch_fmaximum_num(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* fetch_fminimum_num(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr *floating-point-type* fetch_fminimum_num(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_add(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_add(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_sub(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_sub(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_max(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_max(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_min(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_min(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_fmaximum(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_fmaximum(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_fminimum(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_fminimum(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_fmaximum_num(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_fmaximum_num(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; void store_fminimum_num(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_fminimum_num(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) noexcept; *floating-point-type* operator+=(*floating-point-type*) volatile noexcept; constexpr *floating-point-type* operator+=(*floating-point-type*) noexcept; *floating-point-type* operator-=(*floating-point-type*) volatile noexcept; constexpr *floating-point-type* operator-=(*floating-point-type*) noexcept; void wait(*floating-point-type*, memory_order = memory_order::seq_cst) const volatile noexcept; constexpr void wait(*floating-point-type*,
|
||
memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; constexpr void notify_one() noexcept; void notify_all() volatile noexcept; constexpr void notify_all() noexcept; };}
|
||
|
||
[2](#types.float-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5506)
|
||
|
||
The atomic floating-point specializations
|
||
are standard-layout structs[.](#types.float-2.sentence-1)
|
||
|
||
They each have
|
||
a trivial destructor[.](#types.float-2.sentence-2)
|
||
|
||
[3](#types.float-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5512)
|
||
|
||
Descriptions are provided below only for members that differ from the primary template[.](#types.float-3.sentence-1)
|
||
|
||
[4](#types.float-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5515)
|
||
|
||
The following operations perform arithmetic addition and subtraction computations[.](#types.float-4.sentence-1)
|
||
|
||
The correspondence among key, operator, and computation is specified
|
||
in Table [155](#tab:atomic.types.int.comp "Table 155: Atomic arithmetic computations"),
|
||
except for the keysmax,min,fmaximum,fminimum,fmaximum_num, andfminimum_num,
|
||
which are specified below[.](#types.float-4.sentence-2)
|
||
|
||
[ð](#lib:atomic_fetch_add_)
|
||
|
||
`floating-point-type fetch_key(floating-point-type operand,
|
||
memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr floating-point-type fetch_key(floating-point-type operand,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[5](#types.float-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5548)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.float-5.sentence-1)
|
||
|
||
[6](#types.float-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5553)
|
||
|
||
*Effects*: Atomically replaces the value pointed to by this with the result of the computation applied to the value pointed
|
||
to by this and the given operand[.](#types.float-6.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#types.float-6.sentence-2)
|
||
|
||
These operations are atomic read-modify-write operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#types.float-6.sentence-3)
|
||
|
||
[7](#types.float-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5561)
|
||
|
||
*Returns*: Atomically, the value pointed to by this immediately before the effects[.](#types.float-7.sentence-1)
|
||
|
||
[8](#types.float-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5565)
|
||
|
||
*Remarks*: If the result is not a representable value for its type ([[expr.pre]](expr.pre "7.1 Preamble"))
|
||
the result is unspecified, but the operations otherwise have no undefined
|
||
behavior[.](#types.float-8.sentence-1)
|
||
|
||
Atomic arithmetic operations on *floating-point-type* should conform to the std::numeric_limits<*floating-point-type*> traits associated with the floating-point type ([[limits.syn]](limits.syn "17.3.3 Header <limits> synopsis"))[.](#types.float-8.sentence-2)
|
||
|
||
The floating-point environment ([[cfenv]](cfenv "29.3 The floating-point environment")) for atomic arithmetic operations
|
||
on *floating-point-type* may be different than the
|
||
calling thread's floating-point environment[.](#types.float-8.sentence-3)
|
||
|
||
[9](#types.float-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5576)
|
||
|
||
- [(9.1)](#types.float-9.1)
|
||
|
||
For fetch_fmaximum and fetch_fminimum,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum and fminimum, respectively,
|
||
with the value pointed to by this and the first parameter
|
||
as the arguments[.](#types.float-9.1.sentence-1)
|
||
|
||
- [(9.2)](#types.float-9.2)
|
||
|
||
For fetch_fmaximum_num and fetch_fminimum_num,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum_num and fminimum_num, respectively,
|
||
with the value pointed to by this and the first parameter
|
||
as the arguments[.](#types.float-9.2.sentence-1)
|
||
|
||
- [(9.3)](#types.float-9.3)
|
||
|
||
For fetch_max and fetch_min,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum_num and fminimum_num, respectively,
|
||
with the value pointed to by this and the first parameter
|
||
as the arguments, except that:
|
||
* [(9.3.1)](#types.float-9.3.1)
|
||
|
||
If both arguments are NaN,
|
||
an unspecified NaN value replaces the value pointed to by this[.](#types.float-9.3.1.sentence-1)
|
||
|
||
* [(9.3.2)](#types.float-9.3.2)
|
||
|
||
If exactly one argument is a NaN,
|
||
either the other argument or an unspecified NaN value
|
||
replaces the value pointed to by this; it is unspecified which[.](#types.float-9.3.2.sentence-1)
|
||
|
||
* [(9.3.3)](#types.float-9.3.3)
|
||
|
||
If the arguments are differently signed zeros,
|
||
which of these values replaces the value pointed to by this is unspecified[.](#types.float-9.3.3.sentence-1)
|
||
|
||
[10](#types.float-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5610)
|
||
|
||
*Recommended practice*: The implementation of fetch_max and fetch_min should treat negative zero as smaller than positive zero[.](#types.float-10.sentence-1)
|
||
|
||
[ð](#lib:store_max,atomic%3cfloating-point-type%3e)
|
||
|
||
`void store_key(floating-point-type operand,
|
||
memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr void store_key(floating-point-type operand,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[11](#types.float-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5630)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.float-11.sentence-1)
|
||
|
||
[12](#types.float-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5635)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#types.float-12.sentence-1)
|
||
|
||
[13](#types.float-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5642)
|
||
|
||
*Effects*: Atomically replaces the value pointed to by this with the result of the computation applied to
|
||
the value pointed to by this and the given operand[.](#types.float-13.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#types.float-13.sentence-2)
|
||
|
||
These operations are atomic modify-write operations ([[atomics.order]](#order "32.5.4 Order and consistency"))[.](#types.float-13.sentence-3)
|
||
|
||
[14](#types.float-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5650)
|
||
|
||
*Remarks*: If the result is not a representable value for its type ([[expr.pre]](expr.pre "7.1 Preamble"))
|
||
the result is unspecified,
|
||
but the operations otherwise have no undefined behavior[.](#types.float-14.sentence-1)
|
||
|
||
Atomic arithmetic operations on *floating-point-type* should conform to the numeric_limits<*floating-point-type*> traits associated with the floating-point type ([[limits.syn]](limits.syn "17.3.3 Header <limits> synopsis"))[.](#types.float-14.sentence-2)
|
||
|
||
The floating-point environment ([[cfenv]](cfenv "29.3 The floating-point environment")) for
|
||
atomic arithmetic operations on *floating-point-type* may be different than the calling thread's floating-point environment[.](#types.float-14.sentence-3)
|
||
|
||
The arithmetic rules of floating-point atomic modify-write operations
|
||
may be different from operations on
|
||
floating-point types or atomic floating-point types[.](#types.float-14.sentence-4)
|
||
|
||
[*Note [1](#types.float-note-1)*:
|
||
|
||
Tree reductions are permitted for atomic modify-write operations[.](#types.float-14.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[15](#types.float-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5668)
|
||
|
||
- [(15.1)](#types.float-15.1)
|
||
|
||
For store_fmaximum and store_fminimum,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum and fminimum, respectively,
|
||
with the value pointed to by this and
|
||
the first parameter as the arguments[.](#types.float-15.1.sentence-1)
|
||
|
||
- [(15.2)](#types.float-15.2)
|
||
|
||
For store_fmaximum_num and store_fminimum_num,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum_num and fminimum_num, respectively,
|
||
with the value pointed to by this and
|
||
the first parameter as the arguments[.](#types.float-15.2.sentence-1)
|
||
|
||
- [(15.3)](#types.float-15.3)
|
||
|
||
For store_max and store_min,
|
||
the maximum and minimum computation is performed
|
||
as if by fmaximum_num and fminimum_num, respectively,
|
||
with the value pointed to by this and
|
||
the first parameter as the arguments, except that:
|
||
* [(15.3.1)](#types.float-15.3.1)
|
||
|
||
If both arguments are NaN,
|
||
an unspecified NaN value replaces the value pointed to by this[.](#types.float-15.3.1.sentence-1)
|
||
|
||
* [(15.3.2)](#types.float-15.3.2)
|
||
|
||
If exactly one argument is a NaN,
|
||
either the other argument or an unspecified NaN value replaces
|
||
the value pointed to by this;
|
||
it is unspecified which[.](#types.float-15.3.2.sentence-1)
|
||
|
||
* [(15.3.3)](#types.float-15.3.3)
|
||
|
||
If the arguments are differently signed zeros,
|
||
which of these values replaces the value pointed to by this is unspecified[.](#types.float-15.3.3.sentence-1)
|
||
|
||
[16](#types.float-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5703)
|
||
|
||
*Recommended practice*: The implementation of store_max and store_min should treat negative zero as smaller than positive zero[.](#types.float-16.sentence-1)
|
||
|
||
[ð](#lib:operator+=,atomic%3cT*%3e_)
|
||
|
||
`floating-point-type operator op=(floating-point-type operand) volatile noexcept;
|
||
constexpr floating-point-type operator op=(floating-point-type operand) noexcept;
|
||
`
|
||
|
||
[17](#types.float-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5719)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.float-17.sentence-1)
|
||
|
||
[18](#types.float-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5724)
|
||
|
||
*Effects*: Equivalent to: return fetch_*key*(operand) *op* operand;
|
||
|
||
[19](#types.float-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5728)
|
||
|
||
*Remarks*: If the result is not a representable value for its type ([[expr.pre]](expr.pre "7.1 Preamble"))
|
||
the result is unspecified, but the operations otherwise have no undefined
|
||
behavior[.](#types.float-19.sentence-1)
|
||
|
||
Atomic arithmetic operations on *floating-point-type* should conform to the std::numeric_limits<*floating-point-type*> traits associated with the floating-point type ([[limits.syn]](limits.syn "17.3.3 Header <limits> synopsis"))[.](#types.float-19.sentence-2)
|
||
|
||
The floating-point environment ([[cfenv]](cfenv "29.3 The floating-point environment")) for atomic arithmetic operations
|
||
on *floating-point-type* may be different than the
|
||
calling thread's floating-point environment[.](#types.float-19.sentence-3)
|
||
|
||
#### [32.5.8.5](#types.pointer) Partial specialization for pointers [[atomics.types.pointer]](atomics.types.pointer)
|
||
|
||
namespace std {template<class T> struct atomic<T*> {using value_type = T*; using difference_type = ptrdiff_t; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; constexpr atomic() noexcept; constexpr atomic(T*) noexcept;
|
||
atomic(const atomic&) = delete;
|
||
atomic& operator=(const atomic&) = delete;
|
||
atomic& operator=(const atomic&) volatile = delete; void store(T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store(T*, memory_order = memory_order::seq_cst) noexcept;
|
||
T* operator=(T*) volatile noexcept; constexpr T* operator=(T*) noexcept;
|
||
T* load(memory_order = memory_order::seq_cst) const volatile noexcept; constexpr T* load(memory_order = memory_order::seq_cst) const noexcept; operator T*() const volatile noexcept; constexpr operator T*() const noexcept;
|
||
|
||
T* exchange(T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr T* exchange(T*, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_weak(T*&, T*, memory_order, memory_order) noexcept; bool compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile noexcept; constexpr bool compare_exchange_strong(T*&, T*, memory_order, memory_order) noexcept; bool compare_exchange_weak(T*&, T*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_weak(T*&, T*,
|
||
memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(T*&, T*,
|
||
memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool compare_exchange_strong(T*&, T*,
|
||
memory_order = memory_order::seq_cst) noexcept;
|
||
|
||
T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; constexpr T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept;
|
||
T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; constexpr T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept;
|
||
T* fetch_max(T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr T* fetch_max(T*, memory_order = memory_order::seq_cst) noexcept;
|
||
T* fetch_min(T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr T* fetch_min(T*, memory_order = memory_order::seq_cst) noexcept; void store_add(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_add(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; void store_sub(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_sub(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; void store_max(T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_max(T*, memory_order = memory_order::seq_cst) noexcept; void store_min(T*, memory_order = memory_order::seq_cst) volatile noexcept; constexpr void store_min(T*, memory_order = memory_order::seq_cst) noexcept;
|
||
|
||
T* operator++(int) volatile noexcept; constexpr T* operator++(int) noexcept;
|
||
T* operator--(int) volatile noexcept; constexpr T* operator--(int) noexcept;
|
||
T* operator++() volatile noexcept; constexpr T* operator++() noexcept;
|
||
T* operator--() volatile noexcept; constexpr T* operator--() noexcept;
|
||
T* operator+=(ptrdiff_t) volatile noexcept; constexpr T* operator+=(ptrdiff_t) noexcept;
|
||
T* operator-=(ptrdiff_t) volatile noexcept; constexpr T* operator-=(ptrdiff_t) noexcept; void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept; constexpr void wait(T*, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; constexpr void notify_one() noexcept; void notify_all() volatile noexcept; constexpr void notify_all() noexcept; };}
|
||
|
||
[1](#types.pointer-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5825)
|
||
|
||
There is a partial specialization of the atomic class template for pointers[.](#types.pointer-1.sentence-1)
|
||
|
||
Specializations of this partial specialization are standard-layout structs[.](#types.pointer-1.sentence-2)
|
||
|
||
They each have a trivial destructor[.](#types.pointer-1.sentence-3)
|
||
|
||
[2](#types.pointer-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5830)
|
||
|
||
Descriptions are provided below only for members that differ from the primary template[.](#types.pointer-2.sentence-1)
|
||
|
||
[3](#types.pointer-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5833)
|
||
|
||
The following operations perform pointer arithmetic[.](#types.pointer-3.sentence-1)
|
||
|
||
The correspondence among key, operator, and computation is specified
|
||
in Table [156](#tab:atomic.types.pointer.comp "Table 156: Atomic pointer computations")[.](#types.pointer-3.sentence-2)
|
||
|
||
Table [156](#tab:atomic.types.pointer.comp) — Atomic pointer computations [[tab:atomic.types.pointer.comp]](./tab:atomic.types.pointer.comp)
|
||
|
||
| [ð](#tab:atomic.types.pointer.comp-row-1)<br>***key*** | **Op** | **Computation** | ***key*** | **Op** | **Computation** |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| [ð](#tab:atomic.types.pointer.comp-row-2)<br>add | + | addition | sub | - | subtraction |
|
||
| [ð](#tab:atomic.types.pointer.comp-row-3)<br>max | | maximum | min | | minimum |
|
||
|
||
[ð](#lib:atomic_fetch_add__)
|
||
|
||
`T* fetch_key(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr T* fetch_key(ptrdiff_t operand, memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[4](#types.pointer-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5879)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.pointer-4.sentence-1)
|
||
|
||
[5](#types.pointer-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5884)
|
||
|
||
*Mandates*: T is a complete object type[.](#types.pointer-5.sentence-1)
|
||
|
||
[*Note [1](#types.pointer-note-1)*:
|
||
|
||
Pointer arithmetic on void* or function pointers is ill-formed[.](#types.pointer-5.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[6](#types.pointer-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5891)
|
||
|
||
*Effects*: Atomically replaces the value pointed to bythis with the result of the computation applied to the
|
||
value pointed to by this and the given operand[.](#types.pointer-6.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#types.pointer-6.sentence-2)
|
||
|
||
These operations are atomic read-modify-write operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#types.pointer-6.sentence-3)
|
||
|
||
[7](#types.pointer-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5899)
|
||
|
||
*Returns*: Atomically, the value pointed to by this immediately before the effects[.](#types.pointer-7.sentence-1)
|
||
|
||
[8](#types.pointer-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5903)
|
||
|
||
*Remarks*: The result may be an undefined address,
|
||
but the operations otherwise have no undefined behavior[.](#types.pointer-8.sentence-1)
|
||
|
||
[9](#types.pointer-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5908)
|
||
|
||
For fetch_max and fetch_min, the maximum and minimum
|
||
computation is performed as if by max and min algorithms ([[alg.min.max]](alg.min.max "26.8.9 Minimum and maximum")), respectively, with the object value and the first
|
||
parameter as the arguments[.](#types.pointer-9.sentence-1)
|
||
|
||
[*Note [2](#types.pointer-note-2)*:
|
||
|
||
If the pointers point to different complete objects (or subobjects thereof),
|
||
the < operator does not establish a strict weak ordering
|
||
(Table [29](utility.arg.requirements#tab:cpp17.lessthancomparable "Table 29: Cpp17LessThanComparable requirements"), [[expr.rel]](expr.rel "7.6.9 Relational operators"))[.](#types.pointer-9.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:atomic_store_add_)
|
||
|
||
`void store_key(see above operand, memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr void store_key(see above operand, memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[10](#types.pointer-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5939)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.pointer-10.sentence-1)
|
||
|
||
[11](#types.pointer-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5944)
|
||
|
||
*Mandates*: T is a complete object type[.](#types.pointer-11.sentence-1)
|
||
|
||
[*Note [3](#types.pointer-note-3)*:
|
||
|
||
Pointer arithmetic on void* or function pointers is ill-formed[.](#types.pointer-11.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[12](#types.pointer-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5951)
|
||
|
||
*Effects*: Atomically replaces the value pointed to by this with the result of the computation applied to
|
||
the value pointed to by this and the given operand[.](#types.pointer-12.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#types.pointer-12.sentence-2)
|
||
|
||
These operations are atomic modify-write operations ([[atomics.order]](#order "32.5.4 Order and consistency"))[.](#types.pointer-12.sentence-3)
|
||
|
||
[13](#types.pointer-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5959)
|
||
|
||
*Remarks*: The result may be an undefined address,
|
||
but the operations otherwise have no undefined behavior[.](#types.pointer-13.sentence-1)
|
||
|
||
For store_max and store_min,
|
||
the maximum and minimum computation is performed
|
||
as if by max and min algorithms ([[alg.min.max]](alg.min.max "26.8.9 Minimum and maximum")), respectively,
|
||
with the value pointed to by this and
|
||
the first parameter as the arguments[.](#types.pointer-13.sentence-2)
|
||
|
||
[*Note [4](#types.pointer-note-4)*:
|
||
|
||
If the pointers point to different complete objects (or subobjects thereof),
|
||
the < operator does not establish
|
||
a strict weak ordering (Table [29](utility.arg.requirements#tab:cpp17.lessthancomparable "Table 29: Cpp17LessThanComparable requirements"), [[expr.rel]](expr.rel "7.6.9 Relational operators"))[.](#types.pointer-13.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:operator+=,atomic%3cT*%3e__)
|
||
|
||
`T* operator op=(ptrdiff_t operand) volatile noexcept;
|
||
constexpr T* operator op=(ptrdiff_t operand) noexcept;
|
||
`
|
||
|
||
[14](#types.pointer-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5983)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.pointer-14.sentence-1)
|
||
|
||
[15](#types.pointer-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L5988)
|
||
|
||
*Effects*: Equivalent to: return fetch_*key*(operand) *op* operand;
|
||
|
||
#### [32.5.8.6](#types.memop) Member operators common to integers and pointers to objects [[atomics.types.memop]](atomics.types.memop)
|
||
|
||
[ð](#lib:operator++,atomic%3cT*%3e)
|
||
|
||
`value_type operator++(int) volatile noexcept;
|
||
constexpr value_type operator++(int) noexcept;
|
||
`
|
||
|
||
[1](#types.memop-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6003)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.memop-1.sentence-1)
|
||
|
||
[2](#types.memop-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6008)
|
||
|
||
*Effects*: Equivalent to: return fetch_add(1);
|
||
|
||
[ð](#lib:operator--,atomic%3cT*%3e)
|
||
|
||
`value_type operator--(int) volatile noexcept;
|
||
constexpr value_type operator--(int) noexcept;
|
||
`
|
||
|
||
[3](#types.memop-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6021)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.memop-3.sentence-1)
|
||
|
||
[4](#types.memop-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6026)
|
||
|
||
*Effects*: Equivalent to: return fetch_sub(1);
|
||
|
||
[ð](#lib:operator++,atomic%3cT*%3e_)
|
||
|
||
`value_type operator++() volatile noexcept;
|
||
constexpr value_type operator++() noexcept;
|
||
`
|
||
|
||
[5](#types.memop-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6039)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.memop-5.sentence-1)
|
||
|
||
[6](#types.memop-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6044)
|
||
|
||
*Effects*: Equivalent to: return fetch_add(1) + 1;
|
||
|
||
[ð](#lib:operator--,atomic%3cT*%3e_)
|
||
|
||
`value_type operator--() volatile noexcept;
|
||
constexpr value_type operator--() noexcept;
|
||
`
|
||
|
||
[7](#types.memop-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6057)
|
||
|
||
*Constraints*: For the volatile overload of this function,is_always_lock_free is true[.](#types.memop-7.sentence-1)
|
||
|
||
[8](#types.memop-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6062)
|
||
|
||
*Effects*: Equivalent to: return fetch_sub(1) - 1;
|
||
|
||
#### [32.5.8.7](#util.smartptr.atomic) Partial specializations for smart pointers [[util.smartptr.atomic]](util.smartptr.atomic)
|
||
|
||
#### [32.5.8.7.1](#util.smartptr.atomic.general) General [[util.smartptr.atomic.general]](util.smartptr.atomic.general)
|
||
|
||
[1](#util.smartptr.atomic.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6072)
|
||
|
||
The library provides partial specializations of the atomic template
|
||
for shared-ownership smart pointers ([[util.sharedptr]](util.sharedptr "20.3.2 Shared-ownership pointers"))[.](#util.smartptr.atomic.general-1.sentence-1)
|
||
|
||
[*Note [1](#util.smartptr.atomic.general-note-1)*:
|
||
|
||
The partial specializations are declared in header [<memory>](memory.syn#header:%3cmemory%3e "20.2.2 Header <memory> synopsis [memory.syn]")[.](#util.smartptr.atomic.general-1.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
The behavior of all operations is as specified in [[atomics.types.generic]](#types.generic "32.5.8 Class template atomic"),
|
||
unless specified otherwise[.](#util.smartptr.atomic.general-1.sentence-3)
|
||
|
||
The template parameter T of these partial specializations
|
||
may be an incomplete type[.](#util.smartptr.atomic.general-1.sentence-4)
|
||
|
||
[2](#util.smartptr.atomic.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6083)
|
||
|
||
All changes to an atomic smart pointer in [[util.smartptr.atomic]](#util.smartptr.atomic "32.5.8.7 Partial specializations for smart pointers"), and
|
||
all associated use_count increments,
|
||
are guaranteed to be performed atomically[.](#util.smartptr.atomic.general-2.sentence-1)
|
||
|
||
Associated use_count decrements
|
||
are sequenced after the atomic operation,
|
||
but are not required to be part of it[.](#util.smartptr.atomic.general-2.sentence-2)
|
||
|
||
Any associated deletion and deallocation
|
||
are sequenced after the atomic update step and
|
||
are not part of the atomic operation[.](#util.smartptr.atomic.general-2.sentence-3)
|
||
|
||
[*Note [2](#util.smartptr.atomic.general-note-2)*:
|
||
|
||
If the atomic operation uses locks,
|
||
locks acquired by the implementation
|
||
will be held when any use_count adjustments are performed, and
|
||
will not be held when any destruction or deallocation
|
||
resulting from this is performed[.](#util.smartptr.atomic.general-2.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[3](#util.smartptr.atomic.general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6101)
|
||
|
||
[*Example [1](#util.smartptr.atomic.general-example-1)*: template<typename T> class atomic_list {struct node { T t;
|
||
shared_ptr<node> next; };
|
||
atomic<shared_ptr<node>> head;
|
||
|
||
public: shared_ptr<node> find(T t) const {auto p = head.load(); while (p && p->t != t) p = p->next; return p; }void push_front(T t) {auto p = make_shared<node>();
|
||
p->t = t;
|
||
p->next = head; while (!head.compare_exchange_weak(p->next, p)) {}}}; â *end example*]
|
||
|
||
#### [32.5.8.7.2](#util.smartptr.atomic.shared) Partial specialization for shared_ptr [[util.smartptr.atomic.shared]](util.smartptr.atomic.shared)
|
||
|
||
[ð](#lib:atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
namespace std {template<class T> struct atomic<shared_ptr<T>> {using value_type = shared_ptr<T>; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const noexcept; constexpr atomic() noexcept; constexpr atomic(nullptr_t) noexcept : atomic() { }constexpr atomic(shared_ptr<T> desired) noexcept;
|
||
atomic(const atomic&) = delete; void operator=(const atomic&) = delete; constexpr shared_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept; constexpr operator shared_ptr<T>() const noexcept; constexpr void store(shared_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept; constexpr void operator=(shared_ptr<T> desired) noexcept; constexpr void operator=(nullptr_t) noexcept; constexpr shared_ptr<T> exchange(shared_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept; constexpr bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
|
||
memory_order success, memory_order failure) noexcept; constexpr bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
|
||
memory_order success, memory_order failure) noexcept; constexpr bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept; constexpr bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept; constexpr void wait(shared_ptr<T> old,
|
||
memory_order order = memory_order::seq_cst) const noexcept; constexpr void notify_one() noexcept; constexpr void notify_all() noexcept; private: shared_ptr<T> p; // *exposition only*};}
|
||
|
||
[ð](#lib:atomic%3cshared_ptr%3cT%3e%3e,constructor)
|
||
|
||
`constexpr atomic() noexcept;
|
||
`
|
||
|
||
[1](#util.smartptr.atomic.shared-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6181)
|
||
|
||
*Effects*: Value-initializes p[.](#util.smartptr.atomic.shared-1.sentence-1)
|
||
|
||
[ð](#lib:atomic%3cshared_ptr%3cT%3e%3e,constructor_)
|
||
|
||
`constexpr atomic(shared_ptr<T> desired) noexcept;
|
||
`
|
||
|
||
[2](#util.smartptr.atomic.shared-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6192)
|
||
|
||
*Effects*: Initializes the object with the value desired[.](#util.smartptr.atomic.shared-2.sentence-1)
|
||
|
||
Initialization is not an atomic operation ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#util.smartptr.atomic.shared-2.sentence-2)
|
||
|
||
[*Note [1](#util.smartptr.atomic.shared-note-1)*:
|
||
|
||
It is possible to have an access to
|
||
an atomic object A race with its construction,
|
||
for example,
|
||
by communicating the address of the just-constructed object A to another thread via memory_order::relaxed operations
|
||
on a suitable atomic pointer variable, and
|
||
then immediately accessing A in the receiving thread[.](#util.smartptr.atomic.shared-2.sentence-3)
|
||
|
||
This results in undefined behavior[.](#util.smartptr.atomic.shared-2.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:store,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void store(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[3](#util.smartptr.atomic.shared-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6214)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#util.smartptr.atomic.shared-3.sentence-1)
|
||
|
||
[4](#util.smartptr.atomic.shared-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6221)
|
||
|
||
*Effects*: Atomically replaces the value pointed to by this with
|
||
the value of desired as if by p.swap(desired)[.](#util.smartptr.atomic.shared-4.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#util.smartptr.atomic.shared-4.sentence-2)
|
||
|
||
[ð](#lib:operator=,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void operator=(shared_ptr<T> desired) noexcept;
|
||
`
|
||
|
||
[5](#util.smartptr.atomic.shared-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6234)
|
||
|
||
*Effects*: Equivalent to store(desired)[.](#util.smartptr.atomic.shared-5.sentence-1)
|
||
|
||
[ð](#lib:operator=,atomic%3cshared_ptr%3cT%3e%3e_)
|
||
|
||
`constexpr void operator=(nullptr_t) noexcept;
|
||
`
|
||
|
||
[6](#util.smartptr.atomic.shared-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6245)
|
||
|
||
*Effects*: Equivalent to store(nullptr)[.](#util.smartptr.atomic.shared-6.sentence-1)
|
||
|
||
[ð](#lib:load,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr shared_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[7](#util.smartptr.atomic.shared-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6256)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#util.smartptr.atomic.shared-7.sentence-1)
|
||
|
||
[8](#util.smartptr.atomic.shared-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6263)
|
||
|
||
*Effects*: Memory is affected according to the value of order[.](#util.smartptr.atomic.shared-8.sentence-1)
|
||
|
||
[9](#util.smartptr.atomic.shared-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6267)
|
||
|
||
*Returns*: Atomically returns p[.](#util.smartptr.atomic.shared-9.sentence-1)
|
||
|
||
[ð](#lib:operator_shared_ptr%3cT%3e,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr operator shared_ptr<T>() const noexcept;
|
||
`
|
||
|
||
[10](#util.smartptr.atomic.shared-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6278)
|
||
|
||
*Effects*: Equivalent to: return load();
|
||
|
||
[ð](#lib:exchange,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr shared_ptr<T> exchange(shared_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[11](#util.smartptr.atomic.shared-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6290)
|
||
|
||
*Effects*: Atomically replaces p with desired as if by p.swap(desired)[.](#util.smartptr.atomic.shared-11.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#util.smartptr.atomic.shared-11.sentence-2)
|
||
|
||
This is an atomic read-modify-write operation ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#util.smartptr.atomic.shared-11.sentence-3)
|
||
|
||
[12](#util.smartptr.atomic.shared-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6297)
|
||
|
||
*Returns*: Atomically returns the value of p immediately before the effects[.](#util.smartptr.atomic.shared-12.sentence-1)
|
||
|
||
[ð](#lib:compare_exchange_weak,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
|
||
memory_order success, memory_order failure) noexcept;
|
||
constexpr bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
|
||
memory_order success, memory_order failure) noexcept;
|
||
`
|
||
|
||
[13](#util.smartptr.atomic.shared-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6312)
|
||
|
||
*Preconditions*: failure ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#util.smartptr.atomic.shared-13.sentence-1)
|
||
|
||
[14](#util.smartptr.atomic.shared-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6319)
|
||
|
||
*Effects*: If p is equivalent to expected,
|
||
assigns desired to p and
|
||
has synchronization semantics corresponding to the value of success,
|
||
otherwise assigns p to expected and
|
||
has synchronization semantics corresponding to the value of failure[.](#util.smartptr.atomic.shared-14.sentence-1)
|
||
|
||
[15](#util.smartptr.atomic.shared-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6327)
|
||
|
||
*Returns*: true if p was equivalent to expected,false otherwise[.](#util.smartptr.atomic.shared-15.sentence-1)
|
||
|
||
[16](#util.smartptr.atomic.shared-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6332)
|
||
|
||
*Remarks*: Two shared_ptr objects are equivalent if
|
||
they store the same pointer value and
|
||
either share ownership or are both empty[.](#util.smartptr.atomic.shared-16.sentence-1)
|
||
|
||
The weak form may fail spuriously[.](#util.smartptr.atomic.shared-16.sentence-2)
|
||
|
||
See [[atomics.types.operations]](#types.operations "32.5.8.2 Operations on atomic types")[.](#util.smartptr.atomic.shared-16.sentence-3)
|
||
|
||
[17](#util.smartptr.atomic.shared-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6339)
|
||
|
||
If the operation returns true,expected is not accessed after the atomic update and
|
||
the operation is an atomic read-modify-write operation ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))
|
||
on the memory pointed to by this[.](#util.smartptr.atomic.shared-17.sentence-1)
|
||
|
||
Otherwise, the operation is an atomic load operation on that memory, andexpected is updated with the existing value
|
||
read from the atomic object in the attempted atomic update[.](#util.smartptr.atomic.shared-17.sentence-2)
|
||
|
||
The use_count update corresponding to the write to expected is part of the atomic operation[.](#util.smartptr.atomic.shared-17.sentence-3)
|
||
|
||
The write to expected itself
|
||
is not required to be part of the atomic operation[.](#util.smartptr.atomic.shared-17.sentence-4)
|
||
|
||
[ð](#lib:compare_exchange_weak,atomic%3cshared_ptr%3cT%3e%3e_)
|
||
|
||
`constexpr bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[18](#util.smartptr.atomic.shared-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6360)
|
||
|
||
*Effects*: Equivalent to:return compare_exchange_weak(expected, desired, order, fail_order); where fail_order is the same as order except that a value of memory_order::acq_rel shall be replaced by the value memory_order::acquire and
|
||
a value of memory_order::release shall be replaced by the value memory_order::relaxed[.](#util.smartptr.atomic.shared-18.sentence-1)
|
||
|
||
[ð](#lib:compare_exchange_strong,atomic%3cshared_ptr%3cT%3e%3e_)
|
||
|
||
`constexpr bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[19](#util.smartptr.atomic.shared-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6380)
|
||
|
||
*Effects*: Equivalent to:return compare_exchange_strong(expected, desired, order, fail_order); where fail_order is the same as order except that a value of memory_order::acq_rel shall be replaced by the value memory_order::acquire and
|
||
a value of memory_order::release shall be replaced by the value memory_order::relaxed[.](#util.smartptr.atomic.shared-19.sentence-1)
|
||
|
||
[ð](#lib:wait,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void wait(shared_ptr<T> old, memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[20](#util.smartptr.atomic.shared-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6399)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#util.smartptr.atomic.shared-20.sentence-1)
|
||
|
||
[21](#util.smartptr.atomic.shared-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6406)
|
||
|
||
*Effects*: Repeatedly performs the following steps, in order:
|
||
|
||
- [(21.1)](#util.smartptr.atomic.shared-21.1)
|
||
|
||
Evaluates load(order) and compares it to old[.](#util.smartptr.atomic.shared-21.1.sentence-1)
|
||
|
||
- [(21.2)](#util.smartptr.atomic.shared-21.2)
|
||
|
||
If the two are not equivalent, returns[.](#util.smartptr.atomic.shared-21.2.sentence-1)
|
||
|
||
- [(21.3)](#util.smartptr.atomic.shared-21.3)
|
||
|
||
Blocks until it
|
||
is unblocked by an atomic notifying operation or is unblocked spuriously[.](#util.smartptr.atomic.shared-21.3.sentence-1)
|
||
|
||
[22](#util.smartptr.atomic.shared-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6419)
|
||
|
||
*Remarks*: Two shared_ptr objects are equivalent
|
||
if they store the same pointer and either share ownership or are both empty[.](#util.smartptr.atomic.shared-22.sentence-1)
|
||
|
||
This function is an atomic waiting operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#util.smartptr.atomic.shared-22.sentence-2)
|
||
|
||
[ð](#lib:notify_one,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void notify_one() noexcept;
|
||
`
|
||
|
||
[23](#util.smartptr.atomic.shared-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6432)
|
||
|
||
*Effects*: Unblocks the execution of at least one atomic waiting operation
|
||
that is eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call,
|
||
if any such atomic waiting operations exist[.](#util.smartptr.atomic.shared-23.sentence-1)
|
||
|
||
[24](#util.smartptr.atomic.shared-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6438)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#util.smartptr.atomic.shared-24.sentence-1)
|
||
|
||
[ð](#lib:notify_all,atomic%3cshared_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void notify_all() noexcept;
|
||
`
|
||
|
||
[25](#util.smartptr.atomic.shared-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6449)
|
||
|
||
*Effects*: Unblocks the execution of all atomic waiting operations
|
||
that are eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call[.](#util.smartptr.atomic.shared-25.sentence-1)
|
||
|
||
[26](#util.smartptr.atomic.shared-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6454)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#util.smartptr.atomic.shared-26.sentence-1)
|
||
|
||
#### [32.5.8.7.3](#util.smartptr.atomic.weak) Partial specialization for weak_ptr [[util.smartptr.atomic.weak]](util.smartptr.atomic.weak)
|
||
|
||
[ð](#lib:atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
namespace std {template<class T> struct atomic<weak_ptr<T>> {using value_type = weak_ptr<T>; static constexpr bool is_always_lock_free = *implementation-defined*; bool is_lock_free() const noexcept; constexpr atomic() noexcept; constexpr atomic(weak_ptr<T> desired) noexcept;
|
||
atomic(const atomic&) = delete; void operator=(const atomic&) = delete; constexpr weak_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept; constexpr operator weak_ptr<T>() const noexcept; constexpr void store(weak_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept; constexpr void operator=(weak_ptr<T> desired) noexcept; constexpr weak_ptr<T> exchange(weak_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept; constexpr bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
|
||
memory_order success, memory_order failure) noexcept; constexpr bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
|
||
memory_order success, memory_order failure) noexcept; constexpr bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept; constexpr bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept; constexpr void wait(weak_ptr<T> old,
|
||
memory_order order = memory_order::seq_cst) const noexcept; constexpr void notify_one() noexcept; constexpr void notify_all() noexcept; private: weak_ptr<T> p; // *exposition only*};}
|
||
|
||
[ð](#lib:atomic%3cweak_ptr%3cT%3e%3e,constructor)
|
||
|
||
`constexpr atomic() noexcept;
|
||
`
|
||
|
||
[1](#util.smartptr.atomic.weak-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6509)
|
||
|
||
*Effects*: Value-initializes p[.](#util.smartptr.atomic.weak-1.sentence-1)
|
||
|
||
[ð](#lib:atomic%3cweak_ptr%3cT%3e%3e,constructor_)
|
||
|
||
`constexpr atomic(weak_ptr<T> desired) noexcept;
|
||
`
|
||
|
||
[2](#util.smartptr.atomic.weak-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6520)
|
||
|
||
*Effects*: Initializes the object with the value desired[.](#util.smartptr.atomic.weak-2.sentence-1)
|
||
|
||
Initialization is not an atomic operation ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#util.smartptr.atomic.weak-2.sentence-2)
|
||
|
||
[*Note [1](#util.smartptr.atomic.weak-note-1)*:
|
||
|
||
It is possible to have an access to
|
||
an atomic object A race with its construction,
|
||
for example,
|
||
by communicating the address of the just-constructed object A to another thread via memory_order::relaxed operations
|
||
on a suitable atomic pointer variable, and
|
||
then immediately accessing A in the receiving thread[.](#util.smartptr.atomic.weak-2.sentence-3)
|
||
|
||
This results in undefined behavior[.](#util.smartptr.atomic.weak-2.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[ð](#lib:store,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void store(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[3](#util.smartptr.atomic.weak-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6542)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#util.smartptr.atomic.weak-3.sentence-1)
|
||
|
||
[4](#util.smartptr.atomic.weak-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6549)
|
||
|
||
*Effects*: Atomically replaces the value pointed to by this with
|
||
the value of desired as if by p.swap(desired)[.](#util.smartptr.atomic.weak-4.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#util.smartptr.atomic.weak-4.sentence-2)
|
||
|
||
[ð](#lib:operator=,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void operator=(weak_ptr<T> desired) noexcept;
|
||
`
|
||
|
||
[5](#util.smartptr.atomic.weak-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6562)
|
||
|
||
*Effects*: Equivalent to store(desired)[.](#util.smartptr.atomic.weak-5.sentence-1)
|
||
|
||
[ð](#lib:load,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr weak_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[6](#util.smartptr.atomic.weak-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6573)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#util.smartptr.atomic.weak-6.sentence-1)
|
||
|
||
[7](#util.smartptr.atomic.weak-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6580)
|
||
|
||
*Effects*: Memory is affected according to the value of order[.](#util.smartptr.atomic.weak-7.sentence-1)
|
||
|
||
[8](#util.smartptr.atomic.weak-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6584)
|
||
|
||
*Returns*: Atomically returns p[.](#util.smartptr.atomic.weak-8.sentence-1)
|
||
|
||
[ð](#lib:operator_weak_ptr%3cT%3e,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr operator weak_ptr<T>() const noexcept;
|
||
`
|
||
|
||
[9](#util.smartptr.atomic.weak-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6595)
|
||
|
||
*Effects*: Equivalent to: return load();
|
||
|
||
[ð](#lib:exchange,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr weak_ptr<T> exchange(weak_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[10](#util.smartptr.atomic.weak-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6607)
|
||
|
||
*Effects*: Atomically replaces p with desired as if by p.swap(desired)[.](#util.smartptr.atomic.weak-10.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#util.smartptr.atomic.weak-10.sentence-2)
|
||
|
||
This is an atomic read-modify-write operation ([[intro.races]](intro.races "6.10.2.2 Data races"))[.](#util.smartptr.atomic.weak-10.sentence-3)
|
||
|
||
[11](#util.smartptr.atomic.weak-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6614)
|
||
|
||
*Returns*: Atomically returns the value of p immediately before the effects[.](#util.smartptr.atomic.weak-11.sentence-1)
|
||
|
||
[ð](#lib:compare_exchange_weak,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
|
||
memory_order success, memory_order failure) noexcept;
|
||
constexpr bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
|
||
memory_order success, memory_order failure) noexcept;
|
||
`
|
||
|
||
[12](#util.smartptr.atomic.weak-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6628)
|
||
|
||
*Preconditions*: failure ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#util.smartptr.atomic.weak-12.sentence-1)
|
||
|
||
[13](#util.smartptr.atomic.weak-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6635)
|
||
|
||
*Effects*: If p is equivalent to expected,
|
||
assigns desired to p and
|
||
has synchronization semantics corresponding to the value of success,
|
||
otherwise assigns p to expected and
|
||
has synchronization semantics corresponding to the value of failure[.](#util.smartptr.atomic.weak-13.sentence-1)
|
||
|
||
[14](#util.smartptr.atomic.weak-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6643)
|
||
|
||
*Returns*: true if p was equivalent to expected,false otherwise[.](#util.smartptr.atomic.weak-14.sentence-1)
|
||
|
||
[15](#util.smartptr.atomic.weak-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6648)
|
||
|
||
*Remarks*: Two weak_ptr objects are equivalent if
|
||
they store the same pointer value and
|
||
either share ownership or are both empty[.](#util.smartptr.atomic.weak-15.sentence-1)
|
||
|
||
The weak form may fail spuriously[.](#util.smartptr.atomic.weak-15.sentence-2)
|
||
|
||
See [[atomics.types.operations]](#types.operations "32.5.8.2 Operations on atomic types")[.](#util.smartptr.atomic.weak-15.sentence-3)
|
||
|
||
[16](#util.smartptr.atomic.weak-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6655)
|
||
|
||
If the operation returns true,expected is not accessed after the atomic update and
|
||
the operation is an atomic read-modify-write operation ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))
|
||
on the memory pointed to by this[.](#util.smartptr.atomic.weak-16.sentence-1)
|
||
|
||
Otherwise, the operation is an atomic load operation on that memory, andexpected is updated with the existing value
|
||
read from the atomic object in the attempted atomic update[.](#util.smartptr.atomic.weak-16.sentence-2)
|
||
|
||
The use_count update corresponding to the write to expected is part of the atomic operation[.](#util.smartptr.atomic.weak-16.sentence-3)
|
||
|
||
The write to expected itself
|
||
is not required to be part of the atomic operation[.](#util.smartptr.atomic.weak-16.sentence-4)
|
||
|
||
[ð](#lib:compare_exchange_weak,atomic%3cweak_ptr%3cT%3e%3e_)
|
||
|
||
`constexpr bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[17](#util.smartptr.atomic.weak-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6676)
|
||
|
||
*Effects*: Equivalent to:return compare_exchange_weak(expected, desired, order, fail_order); where fail_order is the same as order except that a value of memory_order::acq_rel shall be replaced by the value memory_order::acquire and
|
||
a value of memory_order::release shall be replaced by the value memory_order::relaxed[.](#util.smartptr.atomic.weak-17.sentence-1)
|
||
|
||
[ð](#lib:compare_exchange_strong,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
|
||
memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[18](#util.smartptr.atomic.weak-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6696)
|
||
|
||
*Effects*: Equivalent to:return compare_exchange_strong(expected, desired, order, fail_order); where fail_order is the same as order except that a value of memory_order::acq_rel shall be replaced by the value memory_order::acquire and
|
||
a value of memory_order::release shall be replaced by the value memory_order::relaxed[.](#util.smartptr.atomic.weak-18.sentence-1)
|
||
|
||
[ð](#lib:wait,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void wait(weak_ptr<T> old, memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[19](#util.smartptr.atomic.weak-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6715)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#util.smartptr.atomic.weak-19.sentence-1)
|
||
|
||
[20](#util.smartptr.atomic.weak-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6722)
|
||
|
||
*Effects*: Repeatedly performs the following steps, in order:
|
||
|
||
- [(20.1)](#util.smartptr.atomic.weak-20.1)
|
||
|
||
Evaluates load(order) and compares it to old[.](#util.smartptr.atomic.weak-20.1.sentence-1)
|
||
|
||
- [(20.2)](#util.smartptr.atomic.weak-20.2)
|
||
|
||
If the two are not equivalent, returns[.](#util.smartptr.atomic.weak-20.2.sentence-1)
|
||
|
||
- [(20.3)](#util.smartptr.atomic.weak-20.3)
|
||
|
||
Blocks until it
|
||
is unblocked by an atomic notifying operation or is unblocked spuriously[.](#util.smartptr.atomic.weak-20.3.sentence-1)
|
||
|
||
[21](#util.smartptr.atomic.weak-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6735)
|
||
|
||
*Remarks*: Two weak_ptr objects are equivalent
|
||
if they store the same pointer and either share ownership or are both empty[.](#util.smartptr.atomic.weak-21.sentence-1)
|
||
|
||
This function is an atomic waiting operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#util.smartptr.atomic.weak-21.sentence-2)
|
||
|
||
[ð](#lib:notify_one,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void notify_one() noexcept;
|
||
`
|
||
|
||
[22](#util.smartptr.atomic.weak-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6749)
|
||
|
||
*Effects*: Unblocks the execution of at least one atomic waiting operation
|
||
that is eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call,
|
||
if any such atomic waiting operations exist[.](#util.smartptr.atomic.weak-22.sentence-1)
|
||
|
||
[23](#util.smartptr.atomic.weak-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6755)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#util.smartptr.atomic.weak-23.sentence-1)
|
||
|
||
[ð](#lib:notify_all,atomic%3cweak_ptr%3cT%3e%3e)
|
||
|
||
`constexpr void notify_all() noexcept;
|
||
`
|
||
|
||
[24](#util.smartptr.atomic.weak-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6766)
|
||
|
||
*Effects*: Unblocks the execution of all atomic waiting operations
|
||
that are eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call[.](#util.smartptr.atomic.weak-24.sentence-1)
|
||
|
||
[25](#util.smartptr.atomic.weak-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6771)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#util.smartptr.atomic.weak-25.sentence-1)
|
||
|
||
### [32.5.9](#nonmembers) Non-member functions [[atomics.nonmembers]](atomics.nonmembers)
|
||
|
||
[1](#nonmembers-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6779)
|
||
|
||
A non-member function template whose name matches the patternatomic_*f* or the pattern atomic_*f*_explicit invokes the member function *f*, with the value of the
|
||
first parameter as the object expression and the values of the remaining parameters
|
||
(if any) as the arguments of the member function call, in order[.](#nonmembers-1.sentence-1)
|
||
|
||
An argument
|
||
for a parameter of type atomic<T>::value_type* is dereferenced when
|
||
passed to the member function call[.](#nonmembers-1.sentence-2)
|
||
|
||
If no such member function exists, the program is ill-formed[.](#nonmembers-1.sentence-3)
|
||
|
||
[2](#nonmembers-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6789)
|
||
|
||
[*Note [1](#nonmembers-note-1)*:
|
||
|
||
The non-member functions enable programmers to write code that can be
|
||
compiled as either C or C++, for example in a shared header file[.](#nonmembers-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [32.5.10](#flag) Flag type and operations [[atomics.flag]](atomics.flag)
|
||
|
||
namespace std {struct atomic_flag {constexpr atomic_flag() noexcept;
|
||
atomic_flag(const atomic_flag&) = delete;
|
||
atomic_flag& operator=(const atomic_flag&) = delete;
|
||
atomic_flag& operator=(const atomic_flag&) volatile = delete; bool test(memory_order = memory_order::seq_cst) const volatile noexcept; constexpr bool test(memory_order = memory_order::seq_cst) const noexcept; bool test_and_set(memory_order = memory_order::seq_cst) volatile noexcept; constexpr bool test_and_set(memory_order = memory_order::seq_cst) noexcept; void clear(memory_order = memory_order::seq_cst) volatile noexcept; constexpr void clear(memory_order = memory_order::seq_cst) noexcept; void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept; constexpr void wait(bool, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; constexpr void notify_one() noexcept; void notify_all() volatile noexcept; constexpr void notify_all() noexcept; };}
|
||
|
||
[1](#flag-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6822)
|
||
|
||
The atomic_flag type provides the classic test-and-set functionality[.](#flag-1.sentence-1)
|
||
|
||
It has two states, set and clear[.](#flag-1.sentence-2)
|
||
|
||
[2](#flag-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6825)
|
||
|
||
Operations on an object of type atomic_flag shall be lock-free[.](#flag-2.sentence-1)
|
||
|
||
The operations should also be address-free[.](#flag-2.sentence-2)
|
||
|
||
[3](#flag-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6829)
|
||
|
||
The atomic_flag type is a standard-layout struct[.](#flag-3.sentence-1)
|
||
|
||
It has a trivial destructor[.](#flag-3.sentence-2)
|
||
|
||
[ð](#lib:atomic_flag,constructor)
|
||
|
||
`constexpr atomic_flag::atomic_flag() noexcept;
|
||
`
|
||
|
||
[4](#flag-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6839)
|
||
|
||
*Effects*: Initializes *this to the clear state[.](#flag-4.sentence-1)
|
||
|
||
[ð](#lib:atomic_flag_test)
|
||
|
||
`bool atomic_flag_test(const volatile atomic_flag* object) noexcept;
|
||
constexpr bool atomic_flag_test(const atomic_flag* object) noexcept;
|
||
bool atomic_flag_test_explicit(const volatile atomic_flag* object,
|
||
memory_order order) noexcept;
|
||
constexpr bool atomic_flag_test_explicit(const atomic_flag* object,
|
||
memory_order order) noexcept;
|
||
bool atomic_flag::test(memory_order order = memory_order::seq_cst) const volatile noexcept;
|
||
constexpr bool atomic_flag::test(memory_order order = memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[5](#flag-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6859)
|
||
|
||
For atomic_flag_test, let order be memory_order::seq_cst[.](#flag-5.sentence-1)
|
||
|
||
[6](#flag-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6862)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#flag-6.sentence-1)
|
||
|
||
[7](#flag-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6869)
|
||
|
||
*Effects*: Memory is affected according to the value of order[.](#flag-7.sentence-1)
|
||
|
||
[8](#flag-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6873)
|
||
|
||
*Returns*: Atomically returns the value pointed to by object or this[.](#flag-8.sentence-1)
|
||
|
||
[ð](#lib:atomic_flag_test_and_set)
|
||
|
||
`bool atomic_flag_test_and_set(volatile atomic_flag* object) noexcept;
|
||
constexpr bool atomic_flag_test_and_set(atomic_flag* object) noexcept;
|
||
bool atomic_flag_test_and_set_explicit(volatile atomic_flag* object, memory_order order) noexcept;
|
||
constexpr bool atomic_flag_test_and_set_explicit(atomic_flag* object, memory_order order) noexcept;
|
||
bool atomic_flag::test_and_set(memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr bool atomic_flag::test_and_set(memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[9](#flag-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6891)
|
||
|
||
*Effects*: Atomically sets the value pointed to by object or by this to true[.](#flag-9.sentence-1)
|
||
|
||
Memory is affected according to the value oforder[.](#flag-9.sentence-2)
|
||
|
||
These operations are atomic read-modify-write operations ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#flag-9.sentence-3)
|
||
|
||
[10](#flag-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6896)
|
||
|
||
*Returns*: Atomically, the value of the object immediately before the effects[.](#flag-10.sentence-1)
|
||
|
||
[ð](#lib:atomic_flag_clear)
|
||
|
||
`void atomic_flag_clear(volatile atomic_flag* object) noexcept;
|
||
constexpr void atomic_flag_clear(atomic_flag* object) noexcept;
|
||
void atomic_flag_clear_explicit(volatile atomic_flag* object, memory_order order) noexcept;
|
||
constexpr void atomic_flag_clear_explicit(atomic_flag* object, memory_order order) noexcept;
|
||
void atomic_flag::clear(memory_order order = memory_order::seq_cst) volatile noexcept;
|
||
constexpr void atomic_flag::clear(memory_order order = memory_order::seq_cst) noexcept;
|
||
`
|
||
|
||
[11](#flag-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6914)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::release, ormemory_order::seq_cst[.](#flag-11.sentence-1)
|
||
|
||
[12](#flag-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6921)
|
||
|
||
*Effects*: Atomically sets the value pointed to by object or by this tofalse[.](#flag-12.sentence-1)
|
||
|
||
Memory is affected according to the value of order[.](#flag-12.sentence-2)
|
||
|
||
[ð](#lib:atomic_flag_wait)
|
||
|
||
`void atomic_flag_wait(const volatile atomic_flag* object, bool old) noexcept;
|
||
constexpr void atomic_flag_wait(const atomic_flag* object, bool old) noexcept;
|
||
void atomic_flag_wait_explicit(const volatile atomic_flag* object,
|
||
bool old, memory_order order) noexcept;
|
||
constexpr void atomic_flag_wait_explicit(const atomic_flag* object,
|
||
bool old, memory_order order) noexcept;
|
||
void atomic_flag::wait(bool old, memory_order order =
|
||
memory_order::seq_cst) const volatile noexcept;
|
||
constexpr void atomic_flag::wait(bool old, memory_order order =
|
||
memory_order::seq_cst) const noexcept;
|
||
`
|
||
|
||
[13](#flag-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6944)
|
||
|
||
For atomic_flag_wait,
|
||
let order be memory_order::seq_cst[.](#flag-13.sentence-1)
|
||
|
||
Let flag be object for the non-member functions andthis for the member functions[.](#flag-13.sentence-2)
|
||
|
||
[14](#flag-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6950)
|
||
|
||
*Preconditions*: order ismemory_order::relaxed,memory_order::acquire, ormemory_order::seq_cst[.](#flag-14.sentence-1)
|
||
|
||
[15](#flag-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6957)
|
||
|
||
*Effects*: Repeatedly performs the following steps, in order:
|
||
|
||
- [(15.1)](#flag-15.1)
|
||
|
||
Evaluates flag->test(order) != old[.](#flag-15.1.sentence-1)
|
||
|
||
- [(15.2)](#flag-15.2)
|
||
|
||
If the result of that evaluation is true, returns[.](#flag-15.2.sentence-1)
|
||
|
||
- [(15.3)](#flag-15.3)
|
||
|
||
Blocks until it
|
||
is unblocked by an atomic notifying operation or is unblocked spuriously[.](#flag-15.3.sentence-1)
|
||
|
||
[16](#flag-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6970)
|
||
|
||
*Remarks*: This function is an atomic waiting operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#flag-16.sentence-1)
|
||
|
||
[ð](#flag-itemdecl:6)
|
||
|
||
`void atomic_flag_notify_one(volatile atomic_flag* object) noexcept;
|
||
constexpr void atomic_flag_notify_one(atomic_flag* object) noexcept;
|
||
void atomic_flag::notify_one() volatile noexcept;
|
||
constexpr void atomic_flag::notify_one() noexcept;
|
||
`
|
||
|
||
[17](#flag-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6983)
|
||
|
||
*Effects*: Unblocks the execution of at least one atomic waiting operation
|
||
that is eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call,
|
||
if any such atomic waiting operations exist[.](#flag-17.sentence-1)
|
||
|
||
[18](#flag-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L6989)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#flag-18.sentence-1)
|
||
|
||
[ð](#flag-itemdecl:7)
|
||
|
||
`void atomic_flag_notify_all(volatile atomic_flag* object) noexcept;
|
||
constexpr void atomic_flag_notify_all(atomic_flag* object) noexcept;
|
||
void atomic_flag::notify_all() volatile noexcept;
|
||
constexpr void atomic_flag::notify_all() noexcept;
|
||
`
|
||
|
||
[19](#flag-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7002)
|
||
|
||
*Effects*: Unblocks the execution of all atomic waiting operations
|
||
that are eligible to be unblocked ([[atomics.wait]](#wait "32.5.6 Waiting and notifying")) by this call[.](#flag-19.sentence-1)
|
||
|
||
[20](#flag-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7007)
|
||
|
||
*Remarks*: This function is an atomic notifying operation ([[atomics.wait]](#wait "32.5.6 Waiting and notifying"))[.](#flag-20.sentence-1)
|
||
|
||
[ð](#flag-itemdecl:8)
|
||
|
||
`#define ATOMIC_FLAG_INIT see below
|
||
`
|
||
|
||
[21](#flag-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7017)
|
||
|
||
*Remarks*: The macro ATOMIC_FLAG_INIT is defined in such a way that
|
||
it can be used to initialize an object of type atomic_flag to the clear state[.](#flag-21.sentence-1)
|
||
|
||
The macro can be used in the form:atomic_flag guard = ATOMIC_FLAG_INIT;
|
||
|
||
It is unspecified whether the macro can be used
|
||
in other initialization contexts[.](#flag-21.sentence-3)
|
||
|
||
For a complete static-duration object, that initialization shall be static[.](#flag-21.sentence-4)
|
||
|
||
### [32.5.11](#fences) Fences [[atomics.fences]](atomics.fences)
|
||
|
||
[1](#fences-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7033)
|
||
|
||
This subclause introduces synchronization primitives called [*fences*](#def:fences)[.](#fences-1.sentence-1)
|
||
|
||
Fences can have
|
||
acquire semantics, release semantics, or both[.](#fences-1.sentence-2)
|
||
|
||
A fence with acquire semantics is called
|
||
an [*acquire fence*](#def:acquire_fence)[.](#fences-1.sentence-3)
|
||
|
||
A fence with release semantics is called a [*release
|
||
fence*](#def:release_fence)[.](#fences-1.sentence-4)
|
||
|
||
[2](#fences-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7039)
|
||
|
||
A release fence A synchronizes with an acquire fence B if there exist
|
||
atomic operations X and Y,
|
||
where Y is not an atomic modify-write operation ([[atomics.order]](#order "32.5.4 Order and consistency")),
|
||
both operating on some atomic objectM, such that A is sequenced before X, X modifiesM, 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[.](#fences-2.sentence-1)
|
||
|
||
[3](#fences-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7049)
|
||
|
||
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[.](#fences-3.sentence-1)
|
||
|
||
[4](#fences-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7057)
|
||
|
||
An atomic operation A that is a release operation on an atomic objectM 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[.](#fences-4.sentence-1)
|
||
|
||
[ð](#lib:atomic_thread_fence)
|
||
|
||
`extern "C" constexpr void atomic_thread_fence(memory_order order) noexcept;
|
||
`
|
||
|
||
[5](#fences-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7070)
|
||
|
||
*Effects*: Depending on the value of order, this operation:
|
||
|
||
- [(5.1)](#fences-5.1)
|
||
|
||
has no effects, if order == memory_order::relaxed;
|
||
|
||
- [(5.2)](#fences-5.2)
|
||
|
||
is an acquire fence, if order == memory_order::acquire;
|
||
|
||
- [(5.3)](#fences-5.3)
|
||
|
||
is a release fence, if order == memory_order::release;
|
||
|
||
- [(5.4)](#fences-5.4)
|
||
|
||
is both an acquire fence and a release fence, if order == memory_order::acq_rel;
|
||
|
||
- [(5.5)](#fences-5.5)
|
||
|
||
is a sequentially consistent acquire and release fence, if order == memory_order::seq_cst[.](#fences-5.sentence-1)
|
||
|
||
[ð](#lib:atomic_signal_fence)
|
||
|
||
`extern "C" constexpr void atomic_signal_fence(memory_order order) noexcept;
|
||
`
|
||
|
||
[6](#fences-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7092)
|
||
|
||
*Effects*: Equivalent to atomic_thread_fence(order), except that
|
||
the resulting ordering constraints are established only between a thread and a
|
||
signal handler executed in the same thread[.](#fences-6.sentence-1)
|
||
|
||
[7](#fences-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7098)
|
||
|
||
[*Note [1](#fences-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[.](#fences-7.sentence-1)
|
||
|
||
Compiler optimizations and reorderings of loads and stores are inhibited in
|
||
the same way as with atomic_thread_fence, but the hardware fence instructions
|
||
that atomic_thread_fence would have inserted are not emitted[.](#fences-7.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
### [32.5.12](#stdatomic.h.syn) C compatibility [[stdatomic.h.syn]](stdatomic.h.syn)
|
||
|
||
The header <stdatomic.h> provides the following definitions:
|
||
|
||
template<class T>using *std-atomic* = std::atomic<T>; // *exposition only*#define _Atomic(T) *std-atomic*<T>#define ATOMIC_BOOL_LOCK_FREE *see below*#define ATOMIC_CHAR_LOCK_FREE *see below*#define ATOMIC_CHAR16_T_LOCK_FREE *see below*#define ATOMIC_CHAR32_T_LOCK_FREE *see below*#define ATOMIC_WCHAR_T_LOCK_FREE *see below*#define ATOMIC_SHORT_LOCK_FREE *see below*#define ATOMIC_INT_LOCK_FREE *see below*#define ATOMIC_LONG_LOCK_FREE *see below*#define ATOMIC_LLONG_LOCK_FREE *see below*#define ATOMIC_POINTER_LOCK_FREE *see below*using std::[memory_order](depr.atomics.order#lib:memory_order "D.23.5 memory_order::consume [depr.atomics.order]"); // *see below*using std::[memory_order_relaxed](#lib:memory_order_relaxed "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[memory_order_consume](#lib:memory_order_consume "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[memory_order_acquire](#lib:memory_order_acquire "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[memory_order_release](#lib:memory_order_release "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[memory_order_acq_rel](#lib:memory_order_acq_rel "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[memory_order_seq_cst](#lib:memory_order_seq_cst "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_flag](#lib:atomic_flag "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_bool](#lib:atomic_bool "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_char](#lib:atomic_char "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_schar](#lib:atomic_schar "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uchar](#lib:atomic_uchar "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_short](#lib:atomic_short "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_ushort](#lib:atomic_ushort "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int](#lib:atomic_int "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint](#lib:atomic_uint "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_long](#lib:atomic_long "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_ulong](#lib:atomic_ulong "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_llong](#lib:atomic_llong "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_ullong](#lib:atomic_ullong "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_char8_t](#lib:atomic_char8_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_char16_t](#lib:atomic_char16_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_char32_t](#lib:atomic_char32_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_wchar_t](#lib:atomic_wchar_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int8_t](#lib:atomic_int8_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint8_t](#lib:atomic_uint8_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int16_t](#lib:atomic_int16_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint16_t](#lib:atomic_uint16_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int32_t](#lib:atomic_int32_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint32_t](#lib:atomic_uint32_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int64_t](#lib:atomic_int64_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint64_t](#lib:atomic_uint64_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int_least8_t](#lib:atomic_int_least8_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint_least8_t](#lib:atomic_uint_least8_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int_least16_t](#lib:atomic_int_least16_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint_least16_t](#lib:atomic_uint_least16_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int_least32_t](#lib:atomic_int_least32_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint_least32_t](#lib:atomic_uint_least32_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int_least64_t](#lib:atomic_int_least64_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint_least64_t](#lib:atomic_uint_least64_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int_fast8_t](#lib:atomic_int_fast8_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint_fast8_t](#lib:atomic_uint_fast8_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int_fast16_t](#lib:atomic_int_fast16_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint_fast16_t](#lib:atomic_uint_fast16_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int_fast32_t](#lib:atomic_int_fast32_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint_fast32_t](#lib:atomic_uint_fast32_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_int_fast64_t](#lib:atomic_int_fast64_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uint_fast64_t](#lib:atomic_uint_fast64_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_intptr_t](#lib:atomic_intptr_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uintptr_t](#lib:atomic_uintptr_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_size_t](#lib:atomic_size_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_ptrdiff_t](#lib:atomic_ptrdiff_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_intmax_t](#lib:atomic_intmax_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_uintmax_t](#lib:atomic_uintmax_t "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_is_lock_free](#lib:atomic_is_lock_free "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_load](#lib:atomic_load "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_load_explicit](#lib:atomic_load_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_store](#lib:atomic_store "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_store_explicit](#lib:atomic_store_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_exchange](#lib:atomic_exchange "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_exchange_explicit](#lib:atomic_exchange_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_compare_exchange_strong](#lib:atomic_compare_exchange_strong "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_compare_exchange_strong_explicit](#lib:atomic_compare_exchange_strong_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_compare_exchange_weak](#lib:atomic_compare_exchange_weak "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_compare_exchange_weak_explicit](#lib:atomic_compare_exchange_weak_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_add](#lib:atomic_fetch_add "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_add_explicit](#lib:atomic_fetch_add_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_sub](#lib:atomic_fetch_sub "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_sub_explicit](#lib:atomic_fetch_sub_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_and](#lib:atomic_fetch_and "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_and_explicit](#lib:atomic_fetch_and_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_or](#lib:atomic_fetch_or "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_or_explicit](#lib:atomic_fetch_or_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_xor](#lib:atomic_fetch_xor "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_fetch_xor_explicit](#lib:atomic_fetch_xor_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_flag_test_and_set](#lib:atomic_flag_test_and_set "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_flag_test_and_set_explicit](#lib:atomic_flag_test_and_set_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_flag_clear](#lib:atomic_flag_clear "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_flag_clear_explicit](#lib:atomic_flag_clear_explicit "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*#define ATOMIC_FLAG_INIT *see below*using std::[atomic_thread_fence](#lib:atomic_thread_fence "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*using std::[atomic_signal_fence](#lib:atomic_signal_fence "32.5.12 C compatibility [stdatomic.h.syn]"); // *see below*
|
||
|
||
[1](#stdatomic.h.syn-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7217)
|
||
|
||
Each [*using-declaration*](namespace.udecl#nt:using-declaration "9.10 The using declaration [namespace.udecl]") for some name A in the synopsis above
|
||
makes available the same entity as std::A declared in [<atomic>](#header:%3catomic%3e "32.5.2 Header <atomic> synopsis [atomics.syn]")[.](#stdatomic.h.syn-1.sentence-1)
|
||
|
||
Each macro listed above other than _Atomic(T) is defined as in [<atomic>](#header:%3catomic%3e "32.5.2 Header <atomic> synopsis [atomics.syn]")[.](#stdatomic.h.syn-1.sentence-2)
|
||
|
||
It is unspecified whether [<stdatomic.h>](#header:%3cstdatomic.h%3e "32.5.12 C compatibility [stdatomic.h.syn]") makes available
|
||
any declarations in namespace std[.](#stdatomic.h.syn-1.sentence-3)
|
||
|
||
[2](#stdatomic.h.syn-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7226)
|
||
|
||
Each of the [*using-declaration*](namespace.udecl#nt:using-declaration "9.10 The using declaration [namespace.udecl]")*s* forintN_t, uintN_t, intptr_t, and uintptr_t listed above is defined if and only if the implementation defines
|
||
the corresponding [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") in [[atomics.syn]](#syn "32.5.2 Header <atomic> synopsis")[.](#stdatomic.h.syn-2.sentence-1)
|
||
|
||
[3](#stdatomic.h.syn-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7232)
|
||
|
||
Neither the _Atomic macro,
|
||
nor any of the non-macro global namespace declarations,
|
||
are provided by any C++ standard library header
|
||
other than [<stdatomic.h>](#header:%3cstdatomic.h%3e "32.5.12 C compatibility [stdatomic.h.syn]")[.](#stdatomic.h.syn-3.sentence-1)
|
||
|
||
[4](#stdatomic.h.syn-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L7238)
|
||
|
||
*Recommended practice*: Implementations should ensure
|
||
that C and C++ representations of atomic objects are compatible,
|
||
so that the same object can be accessed as both an _Atomic(T) from C code and an atomic<T> from C++ code[.](#stdatomic.h.syn-4.sentence-1)
|
||
|
||
The representations should be the same, and
|
||
the mechanisms used to ensure atomicity and memory ordering
|
||
should be compatible[.](#stdatomic.h.syn-4.sentence-2)
|