33 Concurrency support library [thread]

33.1 General [thread.general]

The following subclauses describe components to create and manage threads, perform mutual exclusion, and communicate conditions and values between threads, as summarized in Table 144.
Table 144: Concurrency support library summary [tab:thread.summary]
Subclause
Header
Requirements
Stop tokens
<stop_token>
Threads
<thread>
Atomic operations
<atomic>, <stdatomic.h>
Mutual exclusion
<mutex>, <shared_mutex>
Condition variables
<condition_variable>
Semaphores
<semaphore>
Coordination types
<latch>, <barrier>
Futures
<future>
Safe reclamation
<rcu>, <hazard_pointer>

33.2 Requirements [thread.req]

33.2.1 Template parameter names [thread.req.paramname]

Throughout this Clause, the names of template parameters are used to express type requirements.
Predicate is a function object type ([function.objects]).
Let pred denote an lvalue of type Predicate.
Then the expression pred() shall be well-formed and the type decltype(pred()) shall model boolean-testable ([concept.booleantestable]).
The return value of pred(), converted to bool, yields true if the corresponding test condition is satisfied, and false otherwise.
If a template parameter is named Clock, the corresponding template argument shall be a type C that meets the Cpp17Clock requirements ([time.clock.req]); the program is ill-formed if is_clock_v<C> is false.

33.2.2 Exceptions [thread.req.exception]

Some functions described in this Clause are specified to throw exceptions of type system_error ([syserr.syserr]).
Such exceptions are thrown if any of the function's error conditions is detected or a call to an operating system or other underlying API results in an error that prevents the library function from meeting its specifications.
Failure to allocate storage is reported as described in [res.on.exception.handling].
[Example 1: 
Consider a function in this Clause that is specified to throw exceptions of type system_error and specifies error conditions that include operation_not_permitted for a thread that does not have the privilege to perform the operation.
Assume that, during the execution of this function, an errno of EPERM is reported by a POSIX API call used by the implementation.
Since POSIX specifies an errno of EPERM when β€œthe caller does not have the privilege to perform the operation”, the implementation maps EPERM to an error_condition of operation_not_permitted ([syserr]) and an exception of type system_error is thrown.
β€” end example]
The error_code reported by such an exception's code() member function compares equal to one of the conditions specified in the function's error condition element.

33.2.3 Native handles [thread.req.native]

Several classes described in this Clause have members native_handle_type and native_handle.
The presence of these members and their semantics is implementation-defined.
[Note 1: 
These members allow implementations to provide access to implementation details.
Their names are specified to facilitate portable compile-time detection.
Actual use of these members is inherently non-portable.
β€” end note]

33.2.4 Timing specifications [thread.req.timing]

Several functions described in this Clause take an argument to specify a timeout.
These timeouts are specified as either a duration or a time_point type as specified in [time].
Implementations necessarily have some delay in returning from a timeout.
Any overhead in interrupt response, function return, and scheduling induces a β€œquality of implementation” delay, expressed as duration .
Ideally, this delay would be zero.
Further, any contention for processor and memory resources induces a β€œquality of management” delay, expressed as duration .
The delay durations may vary from timeout to timeout, but in all cases shorter is better.
The functions whose names end in _for take an argument that specifies a duration.
These functions produce relative timeouts.
Implementations should use a steady clock to measure time for these functions.304
Given a duration argument , the real-time duration of the timeout is .
The functions whose names end in _until take an argument that specifies a time point.
These functions produce absolute timeouts.
Implementations should use the clock specified in the time point to measure time for these functions.
Given a clock time point argument , the clock time point of the return from timeout should be when the clock is not adjusted during the timeout.
If the clock is adjusted to the time during the timeout, the behavior should be as follows:
  • If , the waiting function should wake as soon as possible, i.e., , since the timeout is already satisfied.
    This specification may result in the total duration of the wait decreasing when measured against a steady clock.
  • If , the waiting function should not time out until Clock​::​now() returns a time , i.e., waking at .
    [Note 1: 
    When the clock is adjusted backwards, this specification can result in the total duration of the wait increasing when measured against a steady clock.
    When the clock is adjusted forwards, this specification can result in the total duration of the wait decreasing when measured against a steady clock.
    β€” end note]
An implementation returns from such a timeout at any point from the time specified above to the time it would return from a steady-clock relative timeout on the difference between and the time point of the call to the _until function.
Recommended practice: Implementations should decrease the duration of the wait when the clock is adjusted forwards.
[Note 2: 
If the clock is not synchronized with a steady clock, e.g., a CPU time clock, these timeouts can fail to provide useful functionality.
β€” end note]
The resolution of timing provided by an implementation depends on both operating system and hardware.
The finest resolution provided by an implementation is called the native resolution.
Implementation-provided clocks that are used for these functions meet the Cpp17TrivialClock requirements ([time.clock.req]).
A function that takes an argument which specifies a timeout will throw if, during its execution, a clock, time point, or time duration throws an exception.
Such exceptions are referred to as timeout-related exceptions.
[Note 3: 
Instantiations of clock, time point and duration types supplied by the implementation as specified in [time.clock] do not throw exceptions.
β€” end note]
304)304)
Implementations for which standard time units are meaningful will typically have a steady clock within their hardware implementation.

33.2.5 Requirements for Cpp17Lockable types [thread.req.lockable]

33.2.5.1 In general [thread.req.lockable.general]

An execution agent is an entity such as a thread that may perform work in parallel with other execution agents.
[Note 1: 
Implementations or users can introduce other kinds of agents such as processes or thread-pool tasks.
β€” end note]
The calling agent is determined by context, e.g., the calling thread that contains the call, and so on.
[Note 2: 
Some lockable objects are β€œagent oblivious” in that they work for any execution agent model because they do not determine or store the agent's ID (e.g., an ordinary spin lock).
β€” end note]
The standard library templates unique_lock ([thread.lock.unique]), shared_lock ([thread.lock.shared]), scoped_lock ([thread.lock.scoped]), lock_guard ([thread.lock.guard]), lock, try_lock ([thread.lock.algorithm]), and condition_variable_any ([thread.condition.condvarany]) all operate on user-supplied lockable objects.
The Cpp17BasicLockable requirements, the Cpp17Lockable requirements, the Cpp17TimedLockable requirements, the Cpp17SharedLockable requirements, and the Cpp17SharedTimedLockable requirements list the requirements imposed by these library types in order to acquire or release ownership of a lock by a given execution agent.
[Note 3: 
The nature of any lock ownership and any synchronization it entails are not part of these requirements.
β€” end note]
A lock on an object m is said to be
  • a non-shared lock if it is acquired by a call to lock, try_lock, try_lock_for, or try_lock_until on m, or
  • a shared lock if it is acquired by a call to lock_shared, try_lock_shared, try_lock_shared_for, or try_lock_shared_until on m.
[Note 4: 
Only the method of lock acquisition is considered; the nature of any lock ownership is not part of these definitions.
β€” end note]

33.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]

A type L meets the Cpp17BasicLockable requirements if the following expressions are well-formed and have the specified semantics (m denotes a value of type L).
m.lock()
Effects: Blocks until a lock can be acquired for the current execution agent.
If an exception is thrown then a lock shall not have been acquired for the current execution agent.
m.unlock()
Preconditions: The current execution agent holds a non-shared lock on m.
Effects: Releases a non-shared lock on m held by the current execution agent.
Throws: Nothing.

33.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]

A type L meets the Cpp17Lockable requirements if it meets the Cpp17BasicLockable requirements and the following expressions are well-formed and have the specified semantics (m denotes a value of type L).
m.try_lock()
Effects: Attempts to acquire a lock for the current execution agent without blocking.
If an exception is thrown then a lock shall not have been acquired for the current execution agent.
Return type: bool.
Returns: true if the lock was acquired, otherwise false.

33.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]

A type L meets the Cpp17TimedLockable requirements if it meets the Cpp17Lockable requirements and the following expressions are well-formed and have the specified semantics (m denotes a value of type L, rel_time denotes a value of an instantiation of duration, and abs_time denotes a value of an instantiation of time_point).
m.try_lock_for(rel_time)
Effects: Attempts to acquire a lock for the current execution agent within the relative timeout ([thread.req.timing]) specified by rel_time.
The function will not return within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent.
If an exception is thrown then a lock has not been acquired for the current execution agent.
Return type: bool.
Returns: true if the lock was acquired, otherwise false.
m.try_lock_until(abs_time)
Effects: Attempts to acquire a lock for the current execution agent before the absolute timeout ([thread.req.timing]) specified by abs_time.
The function will not return before the timeout specified by abs_time unless it has obtained a lock on m for the current execution agent.
If an exception is thrown then a lock has not been acquired for the current execution agent.
Return type: bool.
Returns: true if the lock was acquired, otherwise false.

33.2.5.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]

A type L meets the Cpp17SharedLockable requirements if the following expressions are well-formed, have the specified semantics, and the expression m.try_lock_shared() has type bool (m denotes a value of type L):
m.lock_shared()
Effects: Blocks until a lock can be acquired for the current execution agent.
If an exception is thrown then a lock shall not have been acquired for the current execution agent.
m.try_lock_shared()
Effects: Attempts to acquire a lock for the current execution agent without blocking.
If an exception is thrown then a lock shall not have been acquired for the current execution agent.
Returns: true if the lock was acquired, false otherwise.
m.unlock_shared()
Preconditions: The current execution agent holds a shared lock on m.
Effects: Releases a shared lock on m held by the current execution agent.
Throws: Nothing.

33.2.5.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]

A type L meets the Cpp17SharedTimedLockable requirements if it meets the Cpp17SharedLockable requirements, and the following expressions are well-formed, have type bool, and have the specified semantics (m denotes a value of type L, rel_time denotes a value of a specialization of chrono​::​duration, and abs_time denotes a value of a specialization of chrono​::​time_point).
m.try_lock_shared_for(rel_time)
Effects: Attempts to acquire a lock for the current execution agent within the relative timeout ([thread.req.timing]) specified by rel_time.
The function will not return within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent.
If an exception is thrown then a lock has not been acquired for the current execution agent.
Returns: true if the lock was acquired, false otherwise.
m.try_lock_shared_until(abs_time)
Effects: Attempts to acquire a lock for the current execution agent before the absolute timeout ([thread.req.timing]) specified by abs_time.
The function will not return before the timeout specified by abs_time unless it has obtained a lock on m for the current execution agent.
If an exception is thrown then a lock has not been acquired for the current execution agent.
Returns: true if the lock was acquired, false otherwise.

33.3 Stop tokens [thread.stoptoken]

33.3.1 Introduction [thread.stoptoken.intro]

Subclause [thread.stoptoken] describes components that can be used to asynchronously request that an operation stops execution in a timely manner, typically because the result is no longer required.
Such a request is called a stop request.
stop_source, stop_token, and stop_callback implement semantics of shared ownership of a stop state.
Any stop_source, stop_token, or stop_callback that shares ownership of the same stop state is an associated stop_source, stop_token, or stop_callback, respectively.
The last remaining owner of the stop state automatically releases the resources associated with the stop state.
A stop_token can be passed to an operation which can either
  • actively poll the token to check if there has been a stop request, or
  • register a callback using the stop_callback class template which will be called in the event that a stop request is made.
A stop request made via a stop_source will be visible to all associated stop_token and stop_source objects.
Once a stop request has been made it cannot be withdrawn (a subsequent stop request has no effect).
Callbacks registered via a stop_callback object are called when a stop request is first made by any associated stop_source object.
Calls to the functions request_stop, stop_requested, and stop_possible do not introduce data races.
A call to request_stop that returns true synchronizes with a call to stop_requested on an associated stop_token or stop_source object that returns true.
Registration of a callback synchronizes with the invocation of that callback.

33.3.2 Header <stop_token> synopsis [thread.stoptoken.syn]

namespace std { // [stoptoken], class stop_token class stop_token; // [stopsource], class stop_source class stop_source; // no-shared-stop-state indicator struct nostopstate_t { explicit nostopstate_t() = default; }; inline constexpr nostopstate_t nostopstate{}; // [stopcallback], class template stop_callback template<class Callback> class stop_callback; }

33.3.3 Class stop_token [stoptoken]

33.3.3.1 General [stoptoken.general]

The class stop_token provides an interface for querying whether a stop request has been made (stop_requested) or can ever be made (stop_possible) using an associated stop_source object ([stopsource]).
A stop_token can also be passed to a stop_callback ([stopcallback]) constructor to register a callback to be called when a stop request has been made from an associated stop_source.
namespace std { class stop_token { public: // [stoptoken.cons], constructors, copy, and assignment stop_token() noexcept; stop_token(const stop_token&) noexcept; stop_token(stop_token&&) noexcept; stop_token& operator=(const stop_token&) noexcept; stop_token& operator=(stop_token&&) noexcept; ~stop_token(); void swap(stop_token&) noexcept; // [stoptoken.mem], stop handling [[nodiscard]] bool stop_requested() const noexcept; [[nodiscard]] bool stop_possible() const noexcept; [[nodiscard]] friend bool operator==(const stop_token& lhs, const stop_token& rhs) noexcept; friend void swap(stop_token& lhs, stop_token& rhs) noexcept; }; }

33.3.3.2 Constructors, copy, and assignment [stoptoken.cons]

stop_token() noexcept;
Postconditions: stop_possible() is false and stop_requested() is false.
[Note 1: 
Because the created stop_token object can never receive a stop request, no resources are allocated for a stop state.
β€” end note]
stop_token(const stop_token& rhs) noexcept;
Postconditions: *this == rhs is true.
[Note 2: 
*this and rhs share the ownership of the same stop state, if any.
β€” end note]
stop_token(stop_token&& rhs) noexcept;
Postconditions: *this contains the value of rhs prior to the start of construction and rhs.stop_possible() is false.
~stop_token();
Effects: Releases ownership of the stop state, if any.
stop_token& operator=(const stop_token& rhs) noexcept;
Effects: Equivalent to: stop_token(rhs).swap(*this).
Returns: *this.
stop_token& operator=(stop_token&& rhs) noexcept;
Effects: Equivalent to: stop_token(std​::​move(rhs)).swap(*this).
Returns: *this.
void swap(stop_token& rhs) noexcept;
Effects: Exchanges the values of *this and rhs.

33.3.3.3 Members [stoptoken.mem]

[[nodiscard]] bool stop_requested() const noexcept;
Returns: true if *this has ownership of a stop state that has received a stop request; otherwise, false.
[[nodiscard]] bool stop_possible() const noexcept;
Returns: false if:
  • *this does not have ownership of a stop state, or
  • a stop request was not made and there are no associated stop_source objects;
otherwise, true.

33.3.3.4 Non-member functions [stoptoken.nonmembers]

[[nodiscard]] bool operator==(const stop_token& lhs, const stop_token& rhs) noexcept;
Returns: true if lhs and rhs have ownership of the same stop state or if both lhs and rhs do not have ownership of a stop state; otherwise false.
friend void swap(stop_token& x, stop_token& y) noexcept;
Effects: Equivalent to: x.swap(y).

33.3.4 Class stop_source [stopsource]

33.3.4.1 General [stopsource.general]

The class stop_source implements the semantics of making a stop request.
A stop request made on a stop_source object is visible to all associated stop_source and stop_token ([stoptoken]) objects.
Once a stop request has been made it cannot be withdrawn (a subsequent stop request has no effect).
namespace std { // no-shared-stop-state indicator struct nostopstate_t { explicit nostopstate_t() = default; }; inline constexpr nostopstate_t nostopstate{}; class stop_source { public: // [stopsource.cons], constructors, copy, and assignment stop_source(); explicit stop_source(nostopstate_t) noexcept; stop_source(const stop_source&) noexcept; stop_source(stop_source&&) noexcept; stop_source& operator=(const stop_source&) noexcept; stop_source& operator=(stop_source&&) noexcept; ~stop_source(); void swap(stop_source&) noexcept; // [stopsource.mem], stop handling [[nodiscard]] stop_token get_token() const noexcept; [[nodiscard]] bool stop_possible() const noexcept; [[nodiscard]] bool stop_requested() const noexcept; bool request_stop() noexcept; [[nodiscard]] friend bool operator==(const stop_source& lhs, const stop_source& rhs) noexcept; friend void swap(stop_source& lhs, stop_source& rhs) noexcept; }; }

33.3.4.2 Constructors, copy, and assignment [stopsource.cons]

stop_source();
Effects: Initialises *this to have ownership of a new stop state.
Postconditions: stop_possible() is true and stop_requested() is false.
Throws: bad_alloc if memory cannot be allocated for the stop state.
explicit stop_source(nostopstate_t) noexcept;
Postconditions: stop_possible() is false and stop_requested() is false.
[Note 1: 
No resources are allocated for the state.
β€” end note]
stop_source(const stop_source& rhs) noexcept;
Postconditions: *this == rhs is true.
[Note 2: 
*this and rhs share the ownership of the same stop state, if any.
β€” end note]
stop_source(stop_source&& rhs) noexcept;
Postconditions: *this contains the value of rhs prior to the start of construction and rhs.stop_possible() is false.
~stop_source();
Effects: Releases ownership of the stop state, if any.
stop_source& operator=(const stop_source& rhs) noexcept;
Effects: Equivalent to: stop_source(rhs).swap(*this).
Returns: *this.
stop_source& operator=(stop_source&& rhs) noexcept;
Effects: Equivalent to: stop_source(std​::​move(rhs)).swap(*this).
Returns: *this.
void swap(stop_source& rhs) noexcept;
Effects: Exchanges the values of *this and rhs.

33.3.4.3 Members [stopsource.mem]

[[nodiscard]] stop_token get_token() const noexcept;
Returns: stop_token() if stop_possible() is false; otherwise a new associated stop_token object.
[[nodiscard]] bool stop_possible() const noexcept;
Returns: true if *this has ownership of a stop state; otherwise, false.
[[nodiscard]] bool stop_requested() const noexcept;
Returns: true if *this has ownership of a stop state that has received a stop request; otherwise, false.
bool request_stop() noexcept;
Effects: If *this does not have ownership of a stop state, returns false.
Otherwise, atomically determines whether the owned stop state has received a stop request, and if not, makes a stop request.
The determination and making of the stop request are an atomic read-modify-write operation ([intro.races]).
If the request was made, the callbacks registered by associated stop_callback objects are synchronously called.
If an invocation of a callback exits via an exception then terminate is invoked ([except.terminate]).
[Note 1: 
A stop request includes notifying all condition variables of type condition_variable_any temporarily registered during an interruptible wait ([thread.condvarany.intwait]).
β€” end note]
Postconditions: stop_possible() is false or stop_requested() is true.
Returns: true if this call made a stop request; otherwise false.

33.3.4.4 Non-member functions [stopsource.nonmembers]

[[nodiscard]] friend bool operator==(const stop_source& lhs, const stop_source& rhs) noexcept;
Returns: true if lhs and rhs have ownership of the same stop state or if both lhs and rhs do not have ownership of a stop state; otherwise false.
friend void swap(stop_source& x, stop_source& y) noexcept;
Effects: Equivalent to: x.swap(y).

33.3.5 Class template stop_callback [stopcallback]

33.3.5.1 General [stopcallback.general]

namespace std { template<class Callback> class stop_callback { public: using callback_type = Callback; // [stopcallback.cons], constructors and destructor template<class C> explicit stop_callback(const stop_token& st, C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>); template<class C> explicit stop_callback(stop_token&& st, C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>); ~stop_callback(); stop_callback(const stop_callback&) = delete; stop_callback(stop_callback&&) = delete; stop_callback& operator=(const stop_callback&) = delete; stop_callback& operator=(stop_callback&&) = delete; private: Callback callback; // exposition only }; template<class Callback> stop_callback(stop_token, Callback) -> stop_callback<Callback>; }
Mandates: stop_callback is instantiated with an argument for the template parameter Callback that satisfies both invocable and destructible.
Preconditions: stop_callback is instantiated with an argument for the template parameter Callback that models both invocable and destructible.

33.3.5.2 Constructors and destructor [stopcallback.cons]

template<class C> explicit stop_callback(const stop_token& st, C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>); template<class C> explicit stop_callback(stop_token&& st, C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>);
Constraints: Callback and C satisfy constructible_from<Callback, C>.
Preconditions: Callback and C model constructible_from<Callback, C>.
Effects: Initializes callback with std​::​forward<C>(cb).
If st.stop_requested() is true, then std​::​forward<Callback>(callback)() is evaluated in the current thread before the constructor returns.
Otherwise, if st has ownership of a stop state, acquires shared ownership of that stop state and registers the callback with that stop state such that std​::​forward<Callback>(callback)() is evaluated by the first call to request_stop() on an associated stop_source.
Throws: Any exception thrown by the initialization of callback.
Remarks: If evaluating std​::​forward<Callback>(callback)() exits via an exception, then terminate is invoked ([except.terminate]).
~stop_callback();
Effects: Unregisters the callback from the owned stop state, if any.
The destructor does not block waiting for the execution of another callback registered by an associated stop_callback.
If callback is concurrently executing on another thread, then the return from the invocation of callback strongly happens before ([intro.races]) callback is destroyed.
If callback is executing on the current thread, then the destructor does not block ([defns.block]) waiting for the return from the invocation of callback.
Releases ownership of the stop state, if any.

33.4 Threads [thread.threads]

33.4.1 General [thread.threads.general]

[thread.threads] describes components that can be used to create and manage threads.
[Note 1: 
These threads are intended to map one-to-one with operating system threads.
β€” end note]

33.4.2 Header <thread> synopsis [thread.syn]

#include <compare> // see [compare.syn] namespace std { // [thread.thread.class], class thread class thread; void swap(thread& x, thread& y) noexcept; // [thread.jthread.class], class jthread class jthread; // [thread.thread.this], namespace this_thread namespace this_thread { thread::id get_id() noexcept; void yield() noexcept; template<class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& rel_time); } }

33.4.3 Class thread [thread.thread.class]

33.4.3.1 General [thread.thread.class.general]

The class thread provides a mechanism to create a new thread of execution, to join with a thread (i.e., wait for a thread to complete), and to perform other operations that manage and query the state of a thread.
A thread object uniquely represents a particular thread of execution.
That representation may be transferred to other thread objects in such a way that no two thread objects simultaneously represent the same thread of execution.
A thread of execution is detached when no thread object represents that thread.
Objects of class thread can be in a state that does not represent a thread of execution.
[Note 1: 
A thread object does not represent a thread of execution after default construction, after being moved from, or after a successful call to detach or join.
β€” end note]
namespace std { class thread { public: // [thread.thread.id], class thread​::​id class id; using native_handle_type = implementation-defined; // see [thread.req.native] // construct/copy/destroy thread() noexcept; template<class F, class... Args> explicit thread(F&& f, Args&&... args); ~thread(); thread(const thread&) = delete; thread(thread&&) noexcept; thread& operator=(const thread&) = delete; thread& operator=(thread&&) noexcept; // [thread.thread.member], members void swap(thread&) noexcept; bool joinable() const noexcept; void join(); void detach(); id get_id() const noexcept; native_handle_type native_handle(); // see [thread.req.native] // static members static unsigned int hardware_concurrency() noexcept; }; }

33.4.3.2 Class thread​::​id [thread.thread.id]

namespace std { class thread::id { public: id() noexcept; }; bool operator==(thread::id x, thread::id y) noexcept; strong_ordering operator<=>(thread::id x, thread::id y) noexcept; template<class charT, class traits> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& out, thread::id id); template<class charT> struct formatter<thread::id, charT>; // hash support template<class T> struct hash; template<> struct hash<thread::id>; }
An object of type thread​::​id provides a unique identifier for each thread of execution and a single distinct value for all thread objects that do not represent a thread of execution ([thread.thread.class]).
Each thread of execution has an associated thread​::​id object that is not equal to the thread​::​id object of any other thread of execution and that is not equal to the thread​::​id object of any thread object that does not represent threads of execution.
The text representation for the character type charT of an object of type thread​::​id is an unspecified sequence of charT such that, for two objects of type thread​::​id x and y, if x == y is true, the thread​::​id objects have the same text representation, and if x != y is true, the thread​::​id objects have distinct text representations.
thread​::​id is a trivially copyable class ([class.prop]).
The library may reuse the value of a thread​::​id of a terminated thread that can no longer be joined.
[Note 1: 
Relational operators allow thread​::​id objects to be used as keys in associative containers.
β€” end note]
id() noexcept;
Postconditions: The constructed object does not represent a thread of execution.
bool operator==(thread::id x, thread::id y) noexcept;
Returns: true only if x and y represent the same thread of execution or neither x nor y represents a thread of execution.
strong_ordering operator<=>(thread::id x, thread::id y) noexcept;
Let P(x, y) be an unspecified total ordering over thread​::​id as described in [alg.sorting].
Returns: strong_ordering​::​less if P(x, y) is true.
Otherwise, strong_ordering​::​greater if P(y, x) is true.
Otherwise, strong_ordering​::​equal.
template<class charT, class traits> basic_ostream<charT, traits>& operator<< (basic_ostream<charT, traits>& out, thread::id id);
Effects: Inserts the text representation for charT of id into out.
Returns: out.
template<class charT> struct formatter<thread::id, charT>;
formatter<thread​::​id, charT> interprets format-spec as a thread-id-format-spec.
The syntax of format specifications is as follows:
thread-id-format-spec:
fill-and-align width
[Note 2: 
The productions fill-and-align and width are described in [format.string.std].
β€” end note]
If the align option is omitted it defaults to >.
A thread​::​id object is formatted by writing its text representation for charT to the output with additional padding and adjustments as specified by the format specifiers.
template<> struct hash<thread::id>;
The specialization is enabled ([unord.hash]).

33.4.3.3 Constructors [thread.thread.constr]

thread() noexcept;
Effects: The object does not represent a thread of execution.
Postconditions: get_id() == id().
template<class F, class... Args> explicit thread(F&& f, Args&&... args);
Constraints: remove_cvref_t<F> is not the same type as thread.
Mandates: The following are all true:
  • is_constructible_v<decay_t<F>, F>,
  • (is_constructible_v<decay_t<Args>, Args> && ...), and
  • is_invocable_v<decay_t<F>, decay_t<Args>...>.
Effects: The new thread of execution executes invoke(auto(std::forward<F>(f)), // for invoke, see [func.invoke] auto(std::forward<Args>(args))...) with the values produced by auto being materialized ([conv.rval]) in the constructing thread.
Any return value from this invocation is ignored.
[Note 1: 
This implies that any exceptions not thrown from the invocation of the copy of f will be thrown in the constructing thread, not the new thread.
β€” end note]
If the invocation of invoke terminates with an uncaught exception, terminate is invoked ([except.terminate]).
Synchronization: The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of f.
Postconditions: get_id() != id().
*this represents the newly started thread.
Throws: system_error if unable to start the new thread.
Error conditions:
  • resource_unavailable_try_again β€” the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.
thread(thread&& x) noexcept;
Postconditions: x.get_id() == id() and get_id() returns the value of x.get_id() prior to the start of construction.

33.4.3.4 Destructor [thread.thread.destr]

~thread();
Effects: If joinable(), invokes terminate ([except.terminate]).
Otherwise, has no effects.
[Note 1: 
Either implicitly detaching or joining a joinable() thread in its destructor can result in difficult to debug correctness (for detach) or performance (for join) bugs encountered only when an exception is thrown.
These bugs can be avoided by ensuring that the destructor is never executed while the thread is still joinable.
β€” end note]

33.4.3.5 Assignment [thread.thread.assign]

thread& operator=(thread&& x) noexcept;
Effects: If joinable(), invokes terminate ([except.terminate]).
Otherwise, assigns the state of x to *this and sets x to a default constructed state.
Postconditions: x.get_id() == id() and get_id() returns the value of x.get_id() prior to the assignment.
Returns: *this.

33.4.3.6 Members [thread.thread.member]

void swap(thread& x) noexcept;
Effects: Swaps the state of *this and x.
bool joinable() const noexcept;
Returns: get_id() != id().
void join();
Effects: Blocks until the thread represented by *this has completed.
Synchronization: The completion of the thread represented by *this synchronizes with ([intro.multithread]) the corresponding successful join() return.
[Note 1: 
Operations on *this are not synchronized.
β€” end note]
Postconditions: The thread represented by *this has completed.
get_id() == id().
Throws: system_error when an exception is required ([thread.req.exception]).
Error conditions:
  • resource_deadlock_would_occur β€” if deadlock is detected or get_id() == this_thread​::​​get_id().
  • no_such_process β€” if the thread is not valid.
  • invalid_argument β€” if the thread is not joinable.
void detach();
Effects: The thread represented by *this continues execution without the calling thread blocking.
When detach() returns, *this no longer represents the possibly continuing thread of execution.
When the thread previously represented by *this ends execution, the implementation releases any owned resources.
Postconditions: get_id() == id().
Throws: system_error when an exception is required ([thread.req.exception]).
Error conditions:
  • no_such_process β€” if the thread is not valid.
  • invalid_argument β€” if the thread is not joinable.
id get_id() const noexcept;
Returns: A default constructed id object if *this does not represent a thread, otherwise this_thread​::​get_id() for the thread of execution represented by *this.

33.4.3.7 Static members [thread.thread.static]

unsigned hardware_concurrency() noexcept;
Returns: The number of hardware thread contexts.
[Note 1: 
This value should only be considered to be a hint.
β€” end note]
If this value is not computable or well-defined, an implementation should return 0.

33.4.3.8 Specialized algorithms [thread.thread.algorithm]

void swap(thread& x, thread& y) noexcept;
Effects: As if by x.swap(y).

33.4.4 Class jthread [thread.jthread.class]

33.4.4.1 General [thread.jthread.class.general]

The class jthread provides a mechanism to create a new thread of execution.
The functionality is the same as for class thread ([thread.thread.class]) with the additional abilities to provide a stop_token ([thread.stoptoken]) to the new thread of execution, make stop requests, and automatically join.
namespace std { class jthread { public: // types using id = thread::id; using native_handle_type = thread::native_handle_type; // [thread.jthread.cons], constructors, move, and assignment jthread() noexcept; template<class F, class... Args> explicit jthread(F&& f, Args&&... args); ~jthread(); jthread(const jthread&) = delete; jthread(jthread&&) noexcept; jthread& operator=(const jthread&) = delete; jthread& operator=(jthread&&) noexcept; // [thread.jthread.mem], members void swap(jthread&) noexcept; [[nodiscard]] bool joinable() const noexcept; void join(); void detach(); [[nodiscard]] id get_id() const noexcept; [[nodiscard]] native_handle_type native_handle(); // see [thread.req.native] // [thread.jthread.stop], stop token handling [[nodiscard]] stop_source get_stop_source() noexcept; [[nodiscard]] stop_token get_stop_token() const noexcept; bool request_stop() noexcept; // [thread.jthread.special], specialized algorithms friend void swap(jthread& lhs, jthread& rhs) noexcept; // [thread.jthread.static], static members [[nodiscard]] static unsigned int hardware_concurrency() noexcept; private: stop_source ssource; // exposition only }; }

33.4.4.2 Constructors, move, and assignment [thread.jthread.cons]

jthread() noexcept;
Effects: Constructs a jthread object that does not represent a thread of execution.
Postconditions: get_id() == id() is true and ssource.stop_possible() is false.
template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
Constraints: remove_cvref_t<F> is not the same type as jthread.
Mandates: The following are all true:
  • is_constructible_v<decay_t<F>, F>,
  • (is_constructible_v<decay_t<Args>, Args> && ...), and
  • is_invocable_v<decay_t<F>, decay_t<Args>...> ||
    is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>.
Effects: Initializes ssource.
The new thread of execution executes invoke(auto(std::forward<F>(f)), get_stop_token(), // for invoke, see [func.invoke] auto(std::forward<Args>(args))...) if that expression is well-formed, otherwise invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...) with the values produced by auto being materialized ([conv.rval]) in the constructing thread.
Any return value from this invocation is ignored.
[Note 1: 
This implies that any exceptions not thrown from the invocation of the copy of f will be thrown in the constructing thread, not the new thread.
β€” end note]
If the invoke expression exits via an exception, terminate is called.
Synchronization: The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of f.
Postconditions: get_id() != id() is true and ssource.stop_possible() is true and *this represents the newly started thread.
[Note 2: 
The calling thread can make a stop request only once, because it cannot replace this stop token.
β€” end note]
Throws: system_error if unable to start the new thread.
Error conditions:
  • resource_unavailable_try_again β€” the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.
jthread(jthread&& x) noexcept;
Postconditions: x.get_id() == id() and get_id() returns the value of x.get_id() prior to the start of construction.
ssource has the value of x.ssource prior to the start of construction and x.ssource.stop_possible() is false.
~jthread();
Effects: If joinable() is true, calls request_stop() and then join().
[Note 3: 
Operations on *this are not synchronized.
β€” end note]
jthread& operator=(jthread&& x) noexcept;
Effects: If &x == this is true, there are no effects.
Otherwise, if joinable() is true, calls request_stop() and then join(), then assigns the state of x to *this and sets x to a default constructed state.
Postconditions: get_id() returns the value of x.get_id() prior to the assignment.
ssource has the value of x.ssource prior to the assignment.
Returns: *this.

33.4.4.3 Members [thread.jthread.mem]

void swap(jthread& x) noexcept;
Effects: Exchanges the values of *this and x.
[[nodiscard]] bool joinable() const noexcept;
Returns: get_id() != id().
void join();
Effects: Blocks until the thread represented by *this has completed.
Synchronization: The completion of the thread represented by *this synchronizes with ([intro.multithread]) the corresponding successful join() return.
[Note 1: 
Operations on *this are not synchronized.
β€” end note]
Postconditions: The thread represented by *this has completed.
get_id() == id().
Throws: system_error when an exception is required ([thread.req.exception]).
Error conditions:
  • resource_deadlock_would_occur β€” if deadlock is detected or get_id() == this_thread​::​​get_id().
  • no_such_process β€” if the thread is not valid.
  • invalid_argument β€” if the thread is not joinable.
void detach();
Effects: The thread represented by *this continues execution without the calling thread blocking.
When detach() returns, *this no longer represents the possibly continuing thread of execution.
When the thread previously represented by *this ends execution, the implementation releases any owned resources.
Postconditions: get_id() == id().
Throws: system_error when an exception is required ([thread.req.exception]).
Error conditions:
  • no_such_process β€” if the thread is not valid.
  • invalid_argument β€” if the thread is not joinable.
id get_id() const noexcept;
Returns: A default constructed id object if *this does not represent a thread, otherwise this_thread​::​get_id() for the thread of execution represented by *this.

33.4.4.4 Stop token handling [thread.jthread.stop]

[[nodiscard]] stop_source get_stop_source() noexcept;
Effects: Equivalent to: return ssource;
[[nodiscard]] stop_token get_stop_token() const noexcept;
Effects: Equivalent to: return ssource.get_token();
bool request_stop() noexcept;
Effects: Equivalent to: return ssource.request_stop();

33.4.4.5 Specialized algorithms [thread.jthread.special]

friend void swap(jthread& x, jthread& y) noexcept;
Effects: Equivalent to: x.swap(y).

33.4.4.6 Static members [thread.jthread.static]

[[nodiscard]] static unsigned int hardware_concurrency() noexcept;
Returns: thread​::​hardware_concurrency().

33.4.5 Namespace this_thread [thread.thread.this]

namespace std::this_thread { thread::id get_id() noexcept; void yield() noexcept; template<class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& rel_time); }
thread::id this_thread::get_id() noexcept;
Returns: An object of type thread​::​id that uniquely identifies the current thread of execution.
Every invocation from this thread of execution returns the same value.
The object returned does not compare equal to a default-constructed thread​::​id.
void this_thread::yield() noexcept;
Effects: Offers the implementation the opportunity to reschedule.
Synchronization: None.
template<class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
Effects: Blocks the calling thread for the absolute timeout ([thread.req.timing]) specified by abs_time.
Synchronization: None.
Throws: Timeout-related exceptions ([thread.req.timing]).
template<class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& rel_time);
Effects: Blocks the calling thread for the relative timeout ([thread.req.timing]) specified by rel_time.
Synchronization: None.
Throws: Timeout-related exceptions ([thread.req.timing]).

33.5 Atomic operations [atomics]

33.5.1 General [atomics.general]

Subclause [atomics] describes components for fine-grained atomic access.
This access is provided via operations on atomic objects.

33.5.2 Header <atomic> synopsis [atomics.syn]

namespace std { // [atomics.order], order and consistency enum class memory_order : unspecified; // freestanding inline constexpr memory_order memory_order_relaxed = memory_order::relaxed; // freestanding inline constexpr memory_order memory_order_consume = memory_order::consume; // freestanding inline constexpr memory_order memory_order_acquire = memory_order::acquire; // freestanding inline constexpr memory_order memory_order_release = memory_order::release; // freestanding inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel; // freestanding inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst; // freestanding template<class T> T kill_dependency(T y) noexcept; // freestanding } // [atomics.lockfree], 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 // freestanding namespace std { // [atomics.ref.generic], class template atomic_ref template<class T> struct atomic_ref; // freestanding // [atomics.ref.pointer], partial specialization for pointers template<class T> struct atomic_ref<T*>; // freestanding // [atomics.types.generic], class template atomic template<class T> struct atomic; // freestanding // [atomics.types.pointer], partial specialization for pointers template<class T> struct atomic<T*>; // freestanding // [atomics.nonmembers], non-member functions template<class T> bool atomic_is_lock_free(const volatile atomic<T>*) noexcept; // freestanding template<class T> bool atomic_is_lock_free(const atomic<T>*) noexcept; // freestanding template<class T> void atomic_store(volatile atomic<T>*, // freestanding typename atomic<T>::value_type) noexcept; template<class T> void atomic_store(atomic<T>*, typename atomic<T>::value_type) noexcept; // freestanding template<class T> void atomic_store_explicit(volatile atomic<T>*, // freestanding typename atomic<T>::value_type, memory_order) noexcept; template<class T> void atomic_store_explicit(atomic<T>*, typename atomic<T>::value_type, // freestanding memory_order) noexcept; template<class T> T atomic_load(const volatile atomic<T>*) noexcept; // freestanding template<class T> T atomic_load(const atomic<T>*) noexcept; // freestanding template<class T> T atomic_load_explicit(const volatile atomic<T>*, memory_order) noexcept; // freestanding template<class T> T atomic_load_explicit(const atomic<T>*, memory_order) noexcept; // freestanding template<class T> T atomic_exchange(volatile atomic<T>*, // freestanding typename atomic<T>::value_type) noexcept; template<class T> T atomic_exchange(atomic<T>*, typename atomic<T>::value_type) noexcept; // freestanding template<class T> T atomic_exchange_explicit(volatile atomic<T>*, // freestanding typename atomic<T>::value_type, memory_order) noexcept; template<class T> T atomic_exchange_explicit(atomic<T>*, typename atomic<T>::value_type, // freestanding memory_order) noexcept; template<class T> bool atomic_compare_exchange_weak(volatile atomic<T>*, // freestanding typename atomic<T>::value_type*, typename atomic<T>::value_type) noexcept; template<class T> bool atomic_compare_exchange_weak(atomic<T>*, // freestanding typename atomic<T>::value_type*, typename atomic<T>::value_type) noexcept; template<class T> bool atomic_compare_exchange_strong(volatile atomic<T>*, // freestanding typename atomic<T>::value_type*, typename atomic<T>::value_type) noexcept; template<class T> bool atomic_compare_exchange_strong(atomic<T>*, // freestanding typename atomic<T>::value_type*, typename atomic<T>::value_type) noexcept; template<class T> bool atomic_compare_exchange_weak_explicit(volatile atomic<T>*, // freestanding typename atomic<T>::value_type*, typename atomic<T>::value_type, memory_order, memory_order) noexcept; template<class T> bool atomic_compare_exchange_weak_explicit(atomic<T>*, // freestanding typename 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>*, // freestanding typename atomic<T>::value_type*, typename atomic<T>::value_type, memory_order, memory_order) noexcept; template<class T> bool atomic_compare_exchange_strong_explicit(atomic<T>*, // freestanding typename atomic<T>::value_type*, typename atomic<T>::value_type, memory_order, memory_order) noexcept; template<class T> T atomic_fetch_add(volatile atomic<T>*, // freestanding typename atomic<T>::difference_type) noexcept; template<class T> T atomic_fetch_add(atomic<T>*, typename atomic<T>::difference_type) noexcept; // freestanding template<class T> T atomic_fetch_add_explicit(volatile atomic<T>*, // freestanding typename atomic<T>::difference_type, memory_order) noexcept; template<class T> T atomic_fetch_add_explicit(atomic<T>*, typename atomic<T>::difference_type, // freestanding memory_order) noexcept; template<class T> T atomic_fetch_sub(volatile atomic<T>*, // freestanding typename atomic<T>::difference_type) noexcept; template<class T> T atomic_fetch_sub(atomic<T>*, typename atomic<T>::difference_type) noexcept; // freestanding template<class T> T atomic_fetch_sub_explicit(volatile atomic<T>*, // freestanding typename atomic<T>::difference_type, memory_order) noexcept; template<class T> T atomic_fetch_sub_explicit(atomic<T>*, typename atomic<T>::difference_type, // freestanding memory_order) noexcept; template<class T> T atomic_fetch_and(volatile atomic<T>*, // freestanding typename atomic<T>::value_type) noexcept; template<class T> T atomic_fetch_and(atomic<T>*, typename atomic<T>::value_type) noexcept; // freestanding template<class T> T atomic_fetch_and_explicit(volatile atomic<T>*, // freestanding typename atomic<T>::value_type, memory_order) noexcept; template<class T> T atomic_fetch_and_explicit(atomic<T>*, typename atomic<T>::value_type, // freestanding memory_order) noexcept; template<class T> T atomic_fetch_or(volatile atomic<T>*, // freestanding typename atomic<T>::value_type) noexcept; template<class T> T atomic_fetch_or(atomic<T>*, typename atomic<T>::value_type) noexcept; // freestanding template<class T> T atomic_fetch_or_explicit(volatile atomic<T>*, // freestanding typename atomic<T>::value_type, memory_order) noexcept; template<class T> T atomic_fetch_or_explicit(atomic<T>*, typename atomic<T>::value_type, // freestanding memory_order) noexcept; template<class T> T atomic_fetch_xor(volatile atomic<T>*, // freestanding typename atomic<T>::value_type) noexcept; template<class T> T atomic_fetch_xor(atomic<T>*, typename atomic<T>::value_type) noexcept; // freestanding template<class T> T atomic_fetch_xor_explicit(volatile atomic<T>*, // freestanding typename atomic<T>::value_type, memory_order) noexcept; template<class T> T atomic_fetch_xor_explicit(atomic<T>*, typename atomic<T>::value_type, // freestanding memory_order) noexcept; template<class T> void atomic_wait(const volatile atomic<T>*, // freestanding typename atomic<T>::value_type) noexcept; template<class T> void atomic_wait(const atomic<T>*, typename atomic<T>::value_type) noexcept; // freestanding template<class T> void atomic_wait_explicit(const volatile atomic<T>*, // freestanding typename atomic<T>::value_type, memory_order) noexcept; template<class T> void atomic_wait_explicit(const atomic<T>*, typename atomic<T>::value_type, // freestanding memory_order) noexcept; template<class T> void atomic_notify_one(volatile atomic<T>*) noexcept; // freestanding template<class T> void atomic_notify_one(atomic<T>*) noexcept; // freestanding template<class T> void atomic_notify_all(volatile atomic<T>*) noexcept; // freestanding template<class T> void atomic_notify_all(atomic<T>*) noexcept; // freestanding // [atomics.alias], type aliases using atomic_bool = atomic<bool>; // freestanding using atomic_char = atomic<char>; // freestanding using atomic_schar = atomic<signed char>; // freestanding using atomic_uchar = atomic<unsigned char>; // freestanding using atomic_short = atomic<short>; // freestanding using atomic_ushort = atomic<unsigned short>; // freestanding using atomic_int = atomic<int>; // freestanding using atomic_uint = atomic<unsigned int>; // freestanding using atomic_long = atomic<long>; // freestanding using atomic_ulong = atomic<unsigned long>; // freestanding using atomic_llong = atomic<long long>; // freestanding using atomic_ullong = atomic<unsigned long long>; // freestanding using atomic_char8_t = atomic<char8_t>; // freestanding using atomic_char16_t = atomic<char16_t>; // freestanding using atomic_char32_t = atomic<char32_t>; // freestanding using atomic_wchar_t = atomic<wchar_t>; // freestanding using atomic_int8_t = atomic<int8_t>; // freestanding using atomic_uint8_t = atomic<uint8_t>; // freestanding using atomic_int16_t = atomic<int16_t>; // freestanding using atomic_uint16_t = atomic<uint16_t>; // freestanding using atomic_int32_t = atomic<int32_t>; // freestanding using atomic_uint32_t = atomic<uint32_t>; // freestanding using atomic_int64_t = atomic<int64_t>; // freestanding using atomic_uint64_t = atomic<uint64_t>; // freestanding using atomic_int_least8_t = atomic<int_least8_t>; // freestanding using atomic_uint_least8_t = atomic<uint_least8_t>; // freestanding using atomic_int_least16_t = atomic<int_least16_t>; // freestanding using atomic_uint_least16_t = atomic<uint_least16_t>; // freestanding using atomic_int_least32_t = atomic<int_least32_t>; // freestanding using atomic_uint_least32_t = atomic<uint_least32_t>; // freestanding using atomic_int_least64_t = atomic<int_least64_t>; // freestanding using atomic_uint_least64_t = atomic<uint_least64_t>; // freestanding using atomic_int_fast8_t = atomic<int_fast8_t>; // freestanding using atomic_uint_fast8_t = atomic<uint_fast8_t>; // freestanding using atomic_int_fast16_t = atomic<int_fast16_t>; // freestanding using atomic_uint_fast16_t = atomic<uint_fast16_t>; // freestanding using atomic_int_fast32_t = atomic<int_fast32_t>; // freestanding using atomic_uint_fast32_t = atomic<uint_fast32_t>; // freestanding using atomic_int_fast64_t = atomic<int_fast64_t>; // freestanding using atomic_uint_fast64_t = atomic<uint_fast64_t>; // freestanding using atomic_intptr_t = atomic<intptr_t>; // freestanding using atomic_uintptr_t = atomic<uintptr_t>; // freestanding using atomic_size_t = atomic<size_t>; // freestanding using atomic_ptrdiff_t = atomic<ptrdiff_t>; // freestanding using atomic_intmax_t = atomic<intmax_t>; // freestanding using atomic_uintmax_t = atomic<uintmax_t>; // freestanding using atomic_signed_lock_free = see below; using atomic_unsigned_lock_free = see below; // [atomics.flag], flag type and operations struct atomic_flag; // freestanding bool atomic_flag_test(const volatile atomic_flag*) noexcept; // freestanding bool atomic_flag_test(const atomic_flag*) noexcept; // freestanding bool atomic_flag_test_explicit(const volatile atomic_flag*, // freestanding memory_order) noexcept; bool atomic_flag_test_explicit(const atomic_flag*, memory_order) noexcept; // freestanding bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept; // freestanding bool atomic_flag_test_and_set(atomic_flag*) noexcept; // freestanding bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, // freestanding memory_order) noexcept; bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept; // freestanding void atomic_flag_clear(volatile atomic_flag*) noexcept; // freestanding void atomic_flag_clear(atomic_flag*) noexcept; // freestanding void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept; // freestanding void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept; // freestanding void atomic_flag_wait(const volatile atomic_flag*, bool) noexcept; // freestanding void atomic_flag_wait(const atomic_flag*, bool) noexcept; // freestanding void atomic_flag_wait_explicit(const volatile atomic_flag*, // freestanding bool, memory_order) noexcept; void atomic_flag_wait_explicit(const atomic_flag*, // freestanding bool, memory_order) noexcept; void atomic_flag_notify_one(volatile atomic_flag*) noexcept; // freestanding void atomic_flag_notify_one(atomic_flag*) noexcept; // freestanding void atomic_flag_notify_all(volatile atomic_flag*) noexcept; // freestanding void atomic_flag_notify_all(atomic_flag*) noexcept; // freestanding #define ATOMIC_FLAG_INIT see below // freestanding // [atomics.fences], fences extern "C" void atomic_thread_fence(memory_order) noexcept; // freestanding extern "C" void atomic_signal_fence(memory_order) noexcept; // freestanding }

33.5.3 Type aliases [atomics.alias]

The type aliases atomic_intN_t, atomic_uintN_t, atomic_intptr_t, and atomic_uintptr_t are defined if and only if intN_t, uintN_t, intptr_t, and uintptr_t are defined, respectively.
The type aliases atomic_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.
[Note 1: 
These aliases are optional in freestanding implementations ([compliance]).
β€” end note]
Implementations should choose for these aliases the integral specializations of atomic for which the atomic waiting and notifying operations ([atomics.wait]) are most efficient.

33.5.4 Order and consistency [atomics.order]

namespace std { enum class memory_order : unspecified { relaxed, consume, acquire, release, acq_rel, seq_cst }; }
The enumeration memory_order specifies the detailed regular (non-atomic) memory synchronization order as defined in [intro.multithread] and may provide for operation ordering.
Its enumerated values and their meanings are as follows:
  • memory_order​::​relaxed: no operation orders memory.
  • memory_order​::​release, memory_order​::​acq_rel, and memory_order​::​seq_cst: a store operation performs a release operation on the affected memory location.
  • memory_order​::​consume: a load operation performs a consume operation on the affected memory location.
    [Note 1: 
    Prefer memory_order​::​acquire, which provides stronger guarantees than memory_order​::​consume.
    Implementations have found it infeasible to provide performance better than that of memory_order​::​acquire.
    Specification revisions are under consideration.
    β€” end note]
  • memory_order​::​acquire, memory_order​::​acq_rel, and memory_order​::​seq_cst: a load operation performs an acquire operation on the affected memory location.
[Note 2: 
Atomic operations specifying memory_order​::​relaxed are relaxed with respect to memory ordering.
Implementations must still guarantee that any given atomic access to a particular atomic object be indivisible with respect to all other atomic accesses to that object.
β€” end note]
An atomic operation A that performs a release operation on an atomic object M synchronizes with an atomic operation B that performs an acquire operation on M and takes its value from any side effect in the release sequence headed by A.
An atomic operation A on some atomic object M is coherence-ordered before another atomic operation B on M if
  • A is a modification, and B reads the value stored by A, or
  • A precedes B in the modification order of M, or
  • 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 and X precedes B in the modification order of M, or
  • there exists an atomic modification X of M such that A is coherence-ordered before X and X is coherence-ordered before B.
There is a single total order S on all memory_order​::​seq_cst operations, including fences, that satisfies the following constraints.
First, if A and B are memory_order​::​seq_cst operations and A strongly happens before B, then A precedes B in S.
Second, for every pair of atomic operations A and B on an object M, where A is coherence-ordered before B, the following four conditions are required to be satisfied by S:
  • if A and B are both memory_order​::​seq_cst operations, then A precedes B in S; and
  • if A is a memory_order​::​seq_cst operation and B happens before a memory_order​::​seq_cst fence Y, then A precedes Y in S; and
  • if a memory_order​::​seq_cst fence X happens before A and B is a memory_order​::​seq_cst operation, then X precedes B in S; and
  • if a memory_order​::​seq_cst fence X happens before A and B happens before a memory_order​::​seq_cst fence Y, then X precedes Y in S.
[Note 3: 
This definition ensures that S is consistent with the modification order of any atomic object M.
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.
β€” end note]
[Note 4: 
We do not require that S be consistent with β€œhappens before” ([intro.races]).
This allows more efficient implementation of memory_order​::​acquire and memory_order​::​release on some machine architectures.
It can produce surprising results when these are mixed with memory_order​::​seq_cst accesses.
β€” end note]
[Note 5: 
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.
Any use of weaker ordering will invalidate this guarantee unless extreme care is used.
In many cases, memory_order​::​seq_cst atomic operations are reorderable with respect to other atomic operations performed by the same thread.
β€” end note]
Implementations should ensure that no β€œout-of-thin-air” values are computed that circularly depend on their own computation.
[Note 6: 
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.
Note that without this restriction, such an execution is possible.
β€” end note]
[Note 7: 
The recommendation similarly disallows r1 == r2 == 42 in the following example, with x and y again initially zero:
// Thread 1: r1 = x.load(memory_order::relaxed); if (r1 == 42) y.store(42, memory_order::relaxed);
// Thread 2: r2 = y.load(memory_order::relaxed); if (r2 == 42) x.store(42, memory_order::relaxed); β€” end note]
Atomic read-modify-write operations shall always read the last value (in the modification order) written before the write associated with the read-modify-write operation.
Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.
template<class T> T kill_dependency(T y) noexcept;
Effects: The argument does not carry a dependency to the return value ([intro.multithread]).
Returns: y.

33.5.5 Lock-free property [atomics.lockfree]

#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
The ATOMIC_..._LOCK_FREE macros indicate the lock-free property of the corresponding atomic types, with the signed and unsigned variants grouped together.
The properties also apply to the corresponding (partial) specializations of the atomic template.
A value of 0 indicates that the types are never lock-free.
A value of 1 indicates that the types are sometimes lock-free.
A value of 2 indicates that the types are always lock-free.
On a hosted implementation ([compliance]), at least one signed integral specialization of the atomic template, along with the specialization for the corresponding unsigned type ([basic.fundamental]), is always lock-free.
The functions atomic<T>​::​is_lock_free and atomic_is_lock_free ([atomics.types.operations]) indicate whether the object is lock-free.
In any given program execution, the result of the lock-free query is the same for all atomic objects of the same type.
Atomic operations that are not lock-free are considered to potentially block ([intro.progress]).
Recommended practice: Operations that are lock-free should also be address-free.305
The implementation of these operations should not depend on any per-process state.
[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.
β€” end note]
305)305)
That is, atomic operations on the same memory location via two different addresses will communicate atomically.

33.5.6 Waiting and notifying [atomics.wait]

Atomic waiting operations and atomic notifying operations provide a mechanism to wait for the value of an atomic object to change more efficiently than can be achieved with polling.
An atomic waiting operation may block until it is unblocked by an atomic notifying operation, according to each function's effects.
[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.
β€” end note]
[Note 2: 
The following functions are atomic waiting operations:
  • atomic<T>​::​wait,
  • atomic_flag​::​wait,
  • atomic_wait and atomic_wait_explicit,
  • atomic_flag_wait and atomic_flag_wait_explicit, and
  • atomic_ref<T>​::​wait.
β€” end note]
[Note 3: 
The following functions are atomic notifying operations:
  • atomic<T>​::​notify_one and atomic<T>​::​notify_all,
  • atomic_flag​::​notify_one and atomic_flag​::​notify_all,
  • atomic_notify_one and atomic_notify_all,
  • atomic_flag_notify_one and atomic_flag_notify_all, and
  • atomic_ref<T>​::​notify_one and atomic_ref<T>​::​notify_all.
β€” end note]
A call to an atomic waiting operation on an atomic object M is eligible to be unblocked by a call to an atomic notifying operation on M if there exist side effects X and Y on M such that:
  • the atomic waiting operation has blocked after observing the result of X,
  • X precedes Y in the modification order of M, and
  • Y happens before the call to the atomic notifying operation.

33.5.7 Class template atomic_ref [atomics.ref.generic]

33.5.7.1 General [atomics.ref.generic.general]

namespace std { template<class T> struct atomic_ref { private: T* ptr; // exposition only public: using value_type = T; static constexpr size_t required_alignment = implementation-defined; static constexpr bool is_always_lock_free = implementation-defined; bool is_lock_free() const noexcept; explicit atomic_ref(T&); atomic_ref(const atomic_ref&) noexcept; atomic_ref& operator=(const atomic_ref&) = delete; void store(T, memory_order = memory_order::seq_cst) const noexcept; T operator=(T) const noexcept; T load(memory_order = memory_order::seq_cst) const noexcept; operator T() const noexcept; T exchange(T, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_weak(T&, T, memory_order, memory_order) const noexcept; bool compare_exchange_strong(T&, T, memory_order, memory_order) const noexcept; bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept; void wait(T, memory_order = memory_order::seq_cst) const noexcept; void notify_one() const noexcept; void notify_all() const noexcept; }; }
An atomic_ref object applies atomic operations ([atomics.general]) to the object referenced by *ptr such that, for the lifetime ([basic.life]) of the atomic_ref object, the object referenced by *ptr is an atomic object ([intro.races]).
The program is ill-formed if is_trivially_copyable_v<T> is false.
The lifetime ([basic.life]) of an object referenced by *ptr shall exceed the lifetime of all atomic_refs that reference the object.
While any atomic_ref instances exist that reference the *ptr object, all accesses to that object shall exclusively occur through those atomic_ref instances.
No subobject of the object referenced by atomic_ref shall be concurrently referenced by any other atomic_ref object.
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.
[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.
β€” end note]

33.5.7.2 Operations [atomics.ref.ops]

static constexpr size_t required_alignment;
The alignment required for an object to be referenced by an atomic reference, which is at least alignof(T).
[Note 1: 
Hardware could require an object referenced by an atomic_ref to have stricter alignment ([basic.align]) than other objects of type T.
Further, whether operations on an atomic_ref are lock-free could depend on the alignment of the referenced object.
For example, lock-free operations on std​::​complex<double> could be supported only if aligned to 2*alignof(double).
β€” end note]
static constexpr bool is_always_lock_free;
The static data member is_always_lock_free is true if the atomic_ref type's operations are always lock-free, and false otherwise.
bool is_lock_free() const noexcept;
Returns: true if operations on all objects of the type atomic_ref<T> are lock-free, false otherwise.
atomic_ref(T& obj);
Preconditions: The referenced object is aligned to required_alignment.
Postconditions: *this references obj.
Throws: Nothing.
atomic_ref(const atomic_ref& ref) noexcept;
Postconditions: *this references the object referenced by ref.
void store(T desired, memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​release, or memory_order​::​seq_cst.
Effects: Atomically replaces the value referenced by *ptr with the value of desired.
Memory is affected according to the value of order.
T operator=(T desired) const noexcept;
Effects: Equivalent to: store(desired); return desired;
T load(memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Memory is affected according to the value of order.
Returns: Atomically returns the value referenced by *ptr.
operator T() const noexcept;
Effects: Equivalent to: return load();
T exchange(T desired, memory_order order = memory_order::seq_cst) const noexcept;
Effects: Atomically replaces the value referenced by *ptr with desired.
Memory is affected according to the value of order.
This operation is an atomic read-modify-write operation ([intro.multithread]).
Returns: Atomically returns the value referenced by *ptr immediately before the effects.
bool compare_exchange_weak(T& expected, T desired, memory_order success, memory_order failure) const noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order success, memory_order failure) const noexcept; bool compare_exchange_weak(T& expected, T desired, memory_order order = memory_order::seq_cst) const noexcept; bool compare_exchange_strong(T& expected, T desired, memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: failure is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​acquire, or memory_order​::​seq_cst.
Effects: Retrieves the value in expected.
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.
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.
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.
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.
If the operation returns true, these operations are atomic read-modify-write operations ([intro.races]) on the value referenced by *ptr.
Otherwise, these operations are atomic load operations on that memory.
Returns: The result of the comparison.
Remarks: A weak compare-and-exchange operation may fail spuriously.
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.
[Note 2: 
This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g., load-locked store-conditional machines.
A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop.
When a compare-and-exchange is in a loop, the weak version will yield better performance on some platforms.
When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable.
β€” end note]
void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Repeatedly performs the following steps, in order:
  • Evaluates load(order) and compares its value representation for equality against that of old.
  • If they compare unequal, returns.
  • Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.
Remarks: This function is an atomic waiting operation ([atomics.wait]) on atomic object *ptr.
void notify_one() const noexcept;
Effects: Unblocks the execution of at least one atomic waiting operation on *ptr that is eligible to be unblocked ([atomics.wait]) by this call, if any such atomic waiting operations exist.
Remarks: This function is an atomic notifying operation ([atomics.wait]) on atomic object *ptr.
void notify_all() const noexcept;
Effects: Unblocks the execution of all atomic waiting operations on *ptr that are eligible to be unblocked ([atomics.wait]) by this call.
Remarks: This function is an atomic notifying operation ([atomics.wait]) on atomic object *ptr.

33.5.7.3 Specializations for integral types [atomics.ref.int]

There are specializations of the atomic_ref class template for the integral types char, 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>.
For each such type integral-type, the specialization atomic_ref<integral-type> provides additional atomic operations appropriate to integral types.
[Note 1: 
The specialization atomic_ref<bool> uses the primary template ([atomics.ref.generic]).
β€” end note]
namespace std { template<> struct atomic_ref<integral-type> { private: integral-type* ptr; // exposition only public: using value_type = 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; explicit atomic_ref(integral-type&); atomic_ref(const atomic_ref&) noexcept; atomic_ref& operator=(const atomic_ref&) = delete; void store(integral-type, memory_order = memory_order::seq_cst) const noexcept; integral-type operator=(integral-type) const noexcept; integral-type load(memory_order = memory_order::seq_cst) const noexcept; operator integral-type() const noexcept; integral-type exchange(integral-type, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_weak(integral-type&, integral-type, memory_order, memory_order) const noexcept; bool compare_exchange_strong(integral-type&, integral-type, memory_order, memory_order) const noexcept; bool compare_exchange_weak(integral-type&, integral-type, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_strong(integral-type&, integral-type, memory_order = memory_order::seq_cst) const noexcept; integral-type fetch_add(integral-type, memory_order = memory_order::seq_cst) const noexcept; integral-type fetch_sub(integral-type, memory_order = memory_order::seq_cst) const noexcept; integral-type fetch_and(integral-type, memory_order = memory_order::seq_cst) const noexcept; integral-type fetch_or(integral-type, memory_order = memory_order::seq_cst) const noexcept; integral-type fetch_xor(integral-type, memory_order = memory_order::seq_cst) const noexcept; integral-type operator++(int) const noexcept; integral-type operator--(int) const noexcept; integral-type operator++() const noexcept; integral-type operator--() const noexcept; integral-type operator+=(integral-type) const noexcept; integral-type operator-=(integral-type) const noexcept; integral-type operator&=(integral-type) const noexcept; integral-type operator|=(integral-type) const noexcept; integral-type operator^=(integral-type) const noexcept; void wait(integral-type, memory_order = memory_order::seq_cst) const noexcept; void notify_one() const noexcept; void notify_all() const noexcept; }; }
Descriptions are provided below only for members that differ from the primary template.
The following operations perform arithmetic computations.
The correspondence among key, operator, and computation is specified in Table 145.
integral-type fetch_key(integral-type operand, memory_order order = memory_order::seq_cst) const noexcept;
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.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.races]).
Returns: Atomically, the value referenced by *ptr immediately before the effects.
Remarks: 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.
[Note 2: 
There are no undefined results arising from the computation.
β€” end note]
integral-type operator op=(integral-type operand) const noexcept;
Effects: Equivalent to: return fetch_key(operand) op operand;

33.5.7.4 Specializations for floating-point types [atomics.ref.float]

There are specializations of the atomic_ref class template for all cv-unqualified floating-point types.
For each such type floating-point-type, the specialization atomic_ref<floating-point> provides additional atomic operations appropriate to floating-point types.
namespace std { template<> struct atomic_ref<floating-point-type> { private: floating-point-type* ptr; // exposition only public: using value_type = 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; explicit atomic_ref(floating-point-type&); atomic_ref(const atomic_ref&) noexcept; atomic_ref& operator=(const atomic_ref&) = delete; void store(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; floating-point-type operator=(floating-point-type) const noexcept; floating-point-type load(memory_order = memory_order::seq_cst) const noexcept; operator floating-point-type() const noexcept; floating-point-type exchange(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_weak(floating-point-type&, floating-point-type, memory_order, memory_order) const noexcept; bool compare_exchange_strong(floating-point-type&, floating-point-type, memory_order, memory_order) const noexcept; bool compare_exchange_weak(floating-point-type&, floating-point-type, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_strong(floating-point-type&, floating-point-type, memory_order = memory_order::seq_cst) const noexcept; floating-point-type fetch_add(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; floating-point-type fetch_sub(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; floating-point-type operator+=(floating-point-type) const noexcept; floating-point-type operator-=(floating-point-type) const noexcept; void wait(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; void notify_one() const noexcept; void notify_all() const noexcept; }; }
Descriptions are provided below only for members that differ from the primary template.
The following operations perform arithmetic computations.
The correspondence among key, operator, and computation is specified in Table 145.
floating-point-type fetch_key(floating-point-type operand, memory_order order = memory_order::seq_cst) const noexcept;
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.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.races]).
Returns: Atomically, the value referenced by *ptr immediately before the effects.
Remarks: If the result is not a representable value for its type ([expr.pre]), the result is unspecified, but the operations otherwise have no undefined behavior.
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]).
The floating-point environment ([cfenv]) for atomic arithmetic operations on floating-point-type may be different than the calling thread's floating-point environment.
floating-point-type operator op=(floating-point-type operand) const noexcept;
Effects: Equivalent to: return fetch_key(operand) op operand;

33.5.7.5 Partial specialization for pointers [atomics.ref.pointer]

namespace std { template<class T> struct atomic_ref<T*> { private: T** ptr; // exposition only public: using value_type = T*; 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; explicit atomic_ref(T*&); atomic_ref(const atomic_ref&) noexcept; atomic_ref& operator=(const atomic_ref&) = delete; void store(T*, memory_order = memory_order::seq_cst) const noexcept; T* operator=(T*) const noexcept; T* load(memory_order = memory_order::seq_cst) const noexcept; operator T*() const noexcept; T* exchange(T*, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_weak(T*&, T*, memory_order, memory_order) const noexcept; bool compare_exchange_strong(T*&, T*, memory_order, memory_order) const noexcept; bool compare_exchange_weak(T*&, T*, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_strong(T*&, T*, memory_order = memory_order::seq_cst) const noexcept; T* fetch_add(difference_type, memory_order = memory_order::seq_cst) const noexcept; T* fetch_sub(difference_type, memory_order = memory_order::seq_cst) const noexcept; T* operator++(int) const noexcept; T* operator--(int) const noexcept; T* operator++() const noexcept; T* operator--() const noexcept; T* operator+=(difference_type) const noexcept; T* operator-=(difference_type) const noexcept; void wait(T*, memory_order = memory_order::seq_cst) const noexcept; void notify_one() const noexcept; void notify_all() const noexcept; }; }
Descriptions are provided below only for members that differ from the primary template.
The following operations perform arithmetic computations.
The correspondence among key, operator, and computation is specified in Table 146.
T* fetch_key(difference_type operand, memory_order order = memory_order::seq_cst) const noexcept;
Mandates: T is a complete object type.
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.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.races]).
Returns: Atomically, the value referenced by *ptr immediately before the effects.
Remarks: The result may be an undefined address, but the operations otherwise have no undefined behavior.
T* operator op=(difference_type operand) const noexcept;
Effects: Equivalent to: return fetch_key(operand) op operand;

33.5.7.6 Member operators common to integers and pointers to objects [atomics.ref.memop]

value_type operator++(int) const noexcept;
Effects: Equivalent to: return fetch_add(1);
value_type operator--(int) const noexcept;
Effects: Equivalent to: return fetch_sub(1);
value_type operator++() const noexcept;
Effects: Equivalent to: return fetch_add(1) + 1;
value_type operator--() const noexcept;
Effects: Equivalent to: return fetch_sub(1) - 1;

33.5.8 Class template atomic [atomics.types.generic]

33.5.8.1 General [atomics.types.generic.general]

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], operations on atomic types constexpr 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; T load(memory_order = memory_order::seq_cst) const noexcept; operator T() const volatile noexcept; operator T() const noexcept; void store(T, memory_order = memory_order::seq_cst) volatile noexcept; void store(T, memory_order = memory_order::seq_cst) noexcept; T operator=(T) volatile noexcept; T operator=(T) noexcept; T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept; T exchange(T, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(T&, T, memory_order, memory_order) volatile noexcept; bool compare_exchange_weak(T&, T, memory_order, memory_order) noexcept; bool compare_exchange_strong(T&, T, memory_order, memory_order) volatile noexcept; 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; 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; 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; void wait(T, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; void notify_one() noexcept; void notify_all() volatile noexcept; void notify_all() noexcept; }; }
The template argument for T shall meet the Cpp17CopyConstructible and Cpp17CopyAssignable requirements.
The program is ill-formed if any of
  • is_trivially_copyable_v<T>,
  • is_copy_constructible_v<T>,
  • is_move_constructible_v<T>,
  • is_copy_assignable_v<T>, or
  • is_move_assignable_v<T>
is false.
[Note 1: 
Type arguments that are not also statically initializable can be difficult to use.
β€” end note]
The specialization atomic<bool> is a standard-layout struct.
[Note 2: 
The representation of an atomic specialization need not have the same size and alignment requirement as its corresponding argument type.
β€” end note]

33.5.8.2 Operations on atomic types [atomics.types.operations]

constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
Mandates: is_default_constructible_v<T> is true.
Effects: Initializes the atomic object with the value of T().
Initialization is not an atomic operation ([intro.multithread]).
constexpr atomic(T desired) noexcept;
Effects: Initializes the object with the value desired.
Initialization is not an atomic operation ([intro.multithread]).
[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.
This results in undefined behavior.
β€” end note]
static constexpr bool is_always_lock_free = implementation-defined;
The static data member is_always_lock_free is true if the atomic type's operations are always lock-free, and false otherwise.
[Note 2: 
The value of is_always_lock_free is consistent with the value of the corresponding ATOMIC_..._LOCK_FREE macro, if defined.
β€” end note]
bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept;
Returns: true if the object's operations are lock-free, false otherwise.
[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.
β€” end note]
void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; void store(T desired, memory_order order = memory_order::seq_cst) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Preconditions: order is memory_order​::​relaxed, memory_order​::​release, or memory_order​::​seq_cst.
Effects: Atomically replaces the value pointed to by this with the value of desired.
Memory is affected according to the value of order.
T operator=(T desired) volatile noexcept; T operator=(T desired) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to store(desired).
Returns: desired.
T load(memory_order order = memory_order::seq_cst) const volatile noexcept; T load(memory_order order = memory_order::seq_cst) const noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Memory is affected according to the value of order.
Returns: Atomically returns the value pointed to by this.
operator T() const volatile noexcept; operator T() const noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to: return load();
T exchange(T desired, memory_order order = memory_order::seq_cst) volatile noexcept; T exchange(T desired, memory_order order = memory_order::seq_cst) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Atomically replaces the value pointed to by this with desired.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.multithread]).
Returns: Atomically returns the value pointed to by this immediately before the effects.
bool compare_exchange_weak(T& expected, T desired, memory_order success, memory_order failure) volatile noexcept; 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; 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; 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; bool compare_exchange_strong(T& expected, T desired, memory_order order = memory_order::seq_cst) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Preconditions: failure is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​acquire, or memory_order​::​seq_cst.
Effects: Retrieves the value in expected.
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.
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.
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.
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.
If the operation returns true, these operations are atomic read-modify-write operations ([intro.multithread]) on the memory pointed to by this.
Otherwise, these operations are atomic load operations on that memory.
Returns: The result of the comparison.
[Note 4: 
For example, the effect of compare_exchange_strong on objects without padding bits ([basic.types.general]) is if (memcmp(this, &expected, sizeof(*this)) == 0) memcpy(this, &desired, sizeof(*this)); else memcpy(&expected, this, sizeof(*this));
β€” end note]
[Example 1: 
The expected use of the compare-and-exchange operations is as follows.
The compare-and-exchange operations will update expected when another iteration of the loop is needed.
expected = current.load(); do { desired = function(expected); } while (!current.compare_exchange_weak(expected, desired)); β€” end example]
[Example 2: 
Because the expected value is updated only on failure, code releasing the memory containing the expected value on success will work.
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]
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.
Remarks: A weak compare-and-exchange operation may fail spuriously.
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.
[Note 5: 
This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g., load-locked store-conditional machines.
A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop.
When a compare-and-exchange is in a loop, the weak version will yield better performance on some platforms.
When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable.
β€” end note]
[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 with operator== if the value representation has trap bits or alternate representations of the same value.
Notably, on implementations conforming to ISO/IEC/IEEE 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==.
β€” end note]
[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.
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: 
For a union with bits that participate in the value representation of some members but not others, compare-and-exchange might always fail.
This is because such padding bits have an indeterminate value when they do not participate in the value representation of the active member.
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]
void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept; void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Repeatedly performs the following steps, in order:
  • Evaluates load(order) and compares its value representation for equality against that of old.
  • If they compare unequal, returns.
  • Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.
Remarks: This function is an atomic waiting operation ([atomics.wait]).
void notify_one() volatile noexcept; void notify_one() noexcept;
Effects: Unblocks the execution of at least one atomic waiting operation that is eligible to be unblocked ([atomics.wait]) by this call, if any such atomic waiting operations exist.
Remarks: This function is an atomic notifying operation ([atomics.wait]).
void notify_all() volatile noexcept; void notify_all() noexcept;
Effects: Unblocks the execution of all atomic waiting operations that are eligible to be unblocked ([atomics.wait]) by this call.
Remarks: This function is an atomic notifying operation ([atomics.wait]).

33.5.8.3 Specializations for integers [atomics.types.int]

There are specializations of the atomic class template for the integral types char, 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>.
For each such type integral-type, the specialization atomic<integral-type> provides additional atomic operations appropriate to integral types.
[Note 1: 
The specialization atomic<bool> uses the primary template ([atomics.types.generic]).
β€” 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; void store(integral-type, memory_order = memory_order::seq_cst) noexcept; integral-type operator=(integral-type) volatile noexcept; integral-type operator=(integral-type) noexcept; integral-type load(memory_order = memory_order::seq_cst) const volatile noexcept; integral-type load(memory_order = memory_order::seq_cst) const noexcept; operator integral-type() const volatile noexcept; operator integral-type() const noexcept; integral-type exchange(integral-type, memory_order = memory_order::seq_cst) volatile noexcept; 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; 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; 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; 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; 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; 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; 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; 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; 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; integral-type fetch_xor(integral-type, memory_order = memory_order::seq_cst) noexcept; integral-type operator++(int) volatile noexcept; integral-type operator++(int) noexcept; integral-type operator--(int) volatile noexcept; integral-type operator--(int) noexcept; integral-type operator++() volatile noexcept; integral-type operator++() noexcept; integral-type operator--() volatile noexcept; integral-type operator--() noexcept; integral-type operator+=(integral-type) volatile noexcept; integral-type operator+=(integral-type) noexcept; integral-type operator-=(integral-type) volatile noexcept; integral-type operator-=(integral-type) noexcept; integral-type operator&=(integral-type) volatile noexcept; integral-type operator&=(integral-type) noexcept; integral-type operator|=(integral-type) volatile noexcept; integral-type operator|=(integral-type) noexcept; integral-type operator^=(integral-type) volatile noexcept; integral-type operator^=(integral-type) noexcept; void wait(integral-type, memory_order = memory_order::seq_cst) const volatile noexcept; void wait(integral-type, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; void notify_one() noexcept; void notify_all() volatile noexcept; void notify_all() noexcept; }; }
The atomic integral specializations are standard-layout structs.
They each have a trivial destructor.
Descriptions are provided below only for members that differ from the primary template.
The following operations perform arithmetic computations.
The correspondence among key, operator, and computation is specified in Table 145.
Table 145: Atomic arithmetic computations [tab:atomic.types.int.comp]
key
Op
Computation
key
Op
Computation
add
+
addition
sub
-
subtraction
or
|
bitwise inclusive or
xor
^
bitwise exclusive or
and
&
bitwise and
T fetch_key(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; T fetch_key(T operand, memory_order order = memory_order::seq_cst) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
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.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.multithread]).
Returns: Atomically, the value pointed to by this immediately before the effects.
Remarks: 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.
[Note 2: 
There are no undefined results arising from the computation.
β€” end note]
T operator op=(T operand) volatile noexcept; T operator op=(T operand) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to: return fetch_key(operand) op operand;

33.5.8.4 Specializations for floating-point types [atomics.types.float]

There are specializations of the atomic class template for all cv-unqualified floating-point types.
For each such type floating-point-type, the specialization atomic<floating-point-type> provides additional atomic operations appropriate to floating-point types.
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; void store(floating-point-type, memory_order = memory_order::seq_cst) noexcept; floating-point-type operator=(floating-point-type) volatile noexcept; floating-point-type operator=(floating-point-type) noexcept; floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept; floating-point-type load(memory_order = memory_order::seq_cst) noexcept; operator floating-point-type() volatile noexcept; operator floating-point-type() noexcept; floating-point-type exchange(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept; 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; 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; 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; 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; 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; 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; floating-point-type fetch_sub(floating-point-type, memory_order = memory_order::seq_cst) noexcept; floating-point-type operator+=(floating-point-type) volatile noexcept; floating-point-type operator+=(floating-point-type) noexcept; floating-point-type operator-=(floating-point-type) volatile noexcept; floating-point-type operator-=(floating-point-type) noexcept; void wait(floating-point-type, memory_order = memory_order::seq_cst) const volatile noexcept; void wait(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; void notify_one() noexcept; void notify_all() volatile noexcept; void notify_all() noexcept; }; }
The atomic floating-point specializations are standard-layout structs.
They each have a trivial destructor.
Descriptions are provided below only for members that differ from the primary template.
The following operations perform arithmetic addition and subtraction computations.
The correspondence among key, operator, and computation is specified in Table 145.
T fetch_key(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; T fetch_key(T operand, memory_order order = memory_order::seq_cst) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
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.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.multithread]).
Returns: Atomically, the value pointed to by this immediately before the effects.
Remarks: If the result is not a representable value for its type ([expr.pre]) the result is unspecified, but the operations otherwise have no undefined behavior.
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]).
The floating-point environment ([cfenv]) for atomic arithmetic operations on floating-point-type may be different than the calling thread's floating-point environment.
T operator op=(T operand) volatile noexcept; T operator op=(T operand) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to: return fetch_key(operand) op operand;
Remarks: If the result is not a representable value for its type ([expr.pre]) the result is unspecified, but the operations otherwise have no undefined behavior.
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]).
The floating-point environment ([cfenv]) for atomic arithmetic operations on floating-point-type may be different than the calling thread's floating-point environment.

33.5.8.5 Partial specialization for pointers [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; void store(T*, memory_order = memory_order::seq_cst) noexcept; T* operator=(T*) volatile noexcept; T* operator=(T*) noexcept; T* load(memory_order = memory_order::seq_cst) const volatile noexcept; T* load(memory_order = memory_order::seq_cst) const noexcept; operator T*() const volatile noexcept; operator T*() const noexcept; T* exchange(T*, memory_order = memory_order::seq_cst) volatile noexcept; T* exchange(T*, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile noexcept; bool compare_exchange_weak(T*&, T*, memory_order, memory_order) noexcept; bool compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile noexcept; 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; 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; 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; 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; T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept; T* operator++(int) volatile noexcept; T* operator++(int) noexcept; T* operator--(int) volatile noexcept; T* operator--(int) noexcept; T* operator++() volatile noexcept; T* operator++() noexcept; T* operator--() volatile noexcept; T* operator--() noexcept; T* operator+=(ptrdiff_t) volatile noexcept; T* operator+=(ptrdiff_t) noexcept; T* operator-=(ptrdiff_t) volatile noexcept; T* operator-=(ptrdiff_t) noexcept; void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept; void wait(T*, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; void notify_one() noexcept; void notify_all() volatile noexcept; void notify_all() noexcept; }; }
There is a partial specialization of the atomic class template for pointers.
Specializations of this partial specialization are standard-layout structs.
They each have a trivial destructor.
Descriptions are provided below only for members that differ from the primary template.
The following operations perform pointer arithmetic.
The correspondence among key, operator, and computation is specified in Table 146.
Table 146: Atomic pointer computations [tab:atomic.types.pointer.comp]
key
Op
Computation
key
Op
Computation
add
+
addition
sub
-
subtraction
T* fetch_key(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept; T* fetch_key(ptrdiff_t operand, memory_order order = memory_order::seq_cst) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Mandates: T is a complete object type.
[Note 1: 
Pointer arithmetic on void* or function pointers is ill-formed.
β€” end note]
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.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.multithread]).
Returns: Atomically, the value pointed to by this immediately before the effects.
Remarks: The result may be an undefined address, but the operations otherwise have no undefined behavior.
T* operator op=(ptrdiff_t operand) volatile noexcept; T* operator op=(ptrdiff_t operand) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to: return fetch_key(operand) op operand;

33.5.8.6 Member operators common to integers and pointers to objects [atomics.types.memop]

value_type operator++(int) volatile noexcept; value_type operator++(int) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to: return fetch_add(1);
value_type operator--(int) volatile noexcept; value_type operator--(int) noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to: return fetch_sub(1);
value_type operator++() volatile noexcept; value_type operator++() noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to: return fetch_add(1) + 1;
value_type operator--() volatile noexcept; value_type operator--() noexcept;
Constraints: For the volatile overload of this function, is_always_lock_free is true.
Effects: Equivalent to: return fetch_sub(1) - 1;

33.5.8.7 Partial specializations for smart pointers [util.smartptr.atomic]

33.5.8.7.1 General [util.smartptr.atomic.general]

The library provides partial specializations of the atomic template for shared-ownership smart pointers ([util.sharedptr]).
[Note 1: 
The partial specializations are declared in header <memory>.
β€” end note]
The behavior of all operations is as specified in [atomics.types.generic], unless specified otherwise.
The template parameter T of these partial specializations may be an incomplete type.
All changes to an atomic smart pointer in [util.smartptr.atomic], and all associated use_count increments, are guaranteed to be performed atomically.
Associated use_count decrements are sequenced after the atomic operation, but are not required to be part of it.
Any associated deletion and deallocation are sequenced after the atomic update step and are not part of the atomic operation.
[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.
β€” end note]
[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]

33.5.8.7.2 Partial specialization for shared_ptr [util.smartptr.atomic.shared]

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() { } atomic(shared_ptr<T> desired) noexcept; atomic(const atomic&) = delete; void operator=(const atomic&) = delete; shared_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept; operator shared_ptr<T>() const noexcept; void store(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept; void operator=(shared_ptr<T> desired) noexcept; void operator=(nullptr_t) noexcept; shared_ptr<T> exchange(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept; void wait(shared_ptr<T> old, memory_order order = memory_order::seq_cst) const noexcept; void notify_one() noexcept; void notify_all() noexcept; private: shared_ptr<T> p; // exposition only }; }
constexpr atomic() noexcept;
Effects: Initializes p{}.
atomic(shared_ptr<T> desired) noexcept;
Effects: Initializes the object with the value desired.
Initialization is not an atomic operation ([intro.multithread]).
[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.
This results in undefined behavior.
β€” end note]
void store(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​release, or memory_order​::​seq_cst.
Effects: Atomically replaces the value pointed to by this with the value of desired as if by p.swap(desired).
Memory is affected according to the value of order.
void operator=(shared_ptr<T> desired) noexcept;
Effects: Equivalent to store(desired).
void operator=(nullptr_t) noexcept;
Effects: Equivalent to store(nullptr).
shared_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Memory is affected according to the value of order.
Returns: Atomically returns p.
operator shared_ptr<T>() const noexcept;
Effects: Equivalent to: return load();
shared_ptr<T> exchange(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
Effects: Atomically replaces p with desired as if by p.swap(desired).
Memory is affected according to the value of order.
This is an atomic read-modify-write operation ([intro.races]).
Returns: Atomically returns the value of p immediately before the effects.
bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired, memory_order success, memory_order failure) noexcept;
Preconditions: failure is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​acquire, or memory_order​::​seq_cst.
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.
Returns: true if p was equivalent to expected, false otherwise.
Remarks: Two shared_ptr objects are equivalent if they store the same pointer value and either share ownership or are both empty.
The weak form may fail spuriously.
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]) on the memory pointed to by this.
Otherwise, the operation is an atomic load operation on that memory, and expected is updated with the existing value read from the atomic object in the attempted atomic update.
The use_count update corresponding to the write to expected is part of the atomic operation.
The write to expected itself is not required to be part of the atomic operation.
bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
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.
bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
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.
void wait(shared_ptr<T> old, memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Repeatedly performs the following steps, in order:
  • Evaluates load(order) and compares it to old.
  • If the two are not equivalent, returns.
  • Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.
Remarks: Two shared_ptr objects are equivalent if they store the same pointer and either share ownership or are both empty.
This function is an atomic waiting operation ([atomics.wait]).
void notify_one() noexcept;
Effects: Unblocks the execution of at least one atomic waiting operation that is eligible to be unblocked ([atomics.wait]) by this call, if any such atomic waiting operations exist.
Remarks: This function is an atomic notifying operation ([atomics.wait]).
void notify_all() noexcept;
Effects: Unblocks the execution of all atomic waiting operations that are eligible to be unblocked ([atomics.wait]) by this call.
Remarks: This function is an atomic notifying operation ([atomics.wait]).

33.5.8.7.3 Partial specialization for weak_ptr [util.smartptr.atomic.weak]

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; atomic(weak_ptr<T> desired) noexcept; atomic(const atomic&) = delete; void operator=(const atomic&) = delete; weak_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept; operator weak_ptr<T>() const noexcept; void store(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept; void operator=(weak_ptr<T> desired) noexcept; weak_ptr<T> exchange(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept; void wait(weak_ptr<T> old, memory_order order = memory_order::seq_cst) const noexcept; void notify_one() noexcept; void notify_all() noexcept; private: weak_ptr<T> p; // exposition only }; }
constexpr atomic() noexcept;
Effects: Initializes p{}.
atomic(weak_ptr<T> desired) noexcept;
Effects: Initializes the object with the value desired.
Initialization is not an atomic operation ([intro.multithread]).
[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.
This results in undefined behavior.
β€” end note]
void store(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​release, or memory_order​::​seq_cst.
Effects: Atomically replaces the value pointed to by this with the value of desired as if by p.swap(desired).
Memory is affected according to the value of order.
void operator=(weak_ptr<T> desired) noexcept;
Effects: Equivalent to store(desired).
weak_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Memory is affected according to the value of order.
Returns: Atomically returns p.
operator weak_ptr<T>() const noexcept;
Effects: Equivalent to: return load();
weak_ptr<T> exchange(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
Effects: Atomically replaces p with desired as if by p.swap(desired).
Memory is affected according to the value of order.
This is an atomic read-modify-write operation ([intro.races]).
Returns: Atomically returns the value of p immediately before the effects.
bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired, memory_order success, memory_order failure) noexcept;
Preconditions: failure is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​acquire, or memory_order​::​seq_cst.
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.
Returns: true if p was equivalent to expected, false otherwise.
Remarks: Two weak_ptr objects are equivalent if they store the same pointer value and either share ownership or are both empty.
The weak form may fail spuriously.
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]) on the memory pointed to by this.
Otherwise, the operation is an atomic load operation on that memory, and expected is updated with the existing value read from the atomic object in the attempted atomic update.
The use_count update corresponding to the write to expected is part of the atomic operation.
The write to expected itself is not required to be part of the atomic operation.
bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
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.
bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
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.
void wait(weak_ptr<T> old, memory_order order = memory_order::seq_cst) const noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Repeatedly performs the following steps, in order:
  • Evaluates load(order) and compares it to old.
  • If the two are not equivalent, returns.
  • Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.
Remarks: Two weak_ptr objects are equivalent if they store the same pointer and either share ownership or are both empty.
This function is an atomic waiting operation ([atomics.wait]).
void notify_one() noexcept;
Effects: Unblocks the execution of at least one atomic waiting operation that is eligible to be unblocked ([atomics.wait]) by this call, if any such atomic waiting operations exist.
Remarks: This function is an atomic notifying operation ([atomics.wait]).
void notify_all() noexcept;
Effects: Unblocks the execution of all atomic waiting operations that are eligible to be unblocked ([atomics.wait]) by this call.
Remarks: This function is an atomic notifying operation ([atomics.wait]).

33.5.9 Non-member functions [atomics.nonmembers]

A non-member function template whose name matches the pattern atomic_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.
An argument for a parameter of type atomic<T>​::​value_type* is dereferenced when passed to the member function call.
If no such member function exists, the program is ill-formed.
[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.
β€” end note]

33.5.10 Flag type and operations [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; bool test(memory_order = memory_order::seq_cst) const noexcept; bool test_and_set(memory_order = memory_order::seq_cst) volatile noexcept; bool test_and_set(memory_order = memory_order::seq_cst) noexcept; void clear(memory_order = memory_order::seq_cst) volatile noexcept; void clear(memory_order = memory_order::seq_cst) noexcept; void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept; void wait(bool, memory_order = memory_order::seq_cst) const noexcept; void notify_one() volatile noexcept; void notify_one() noexcept; void notify_all() volatile noexcept; void notify_all() noexcept; }; }
The atomic_flag type provides the classic test-and-set functionality.
It has two states, set and clear.
Operations on an object of type atomic_flag shall be lock-free.
The operations should also be address-free.
The atomic_flag type is a standard-layout struct.
It has a trivial destructor.
constexpr atomic_flag::atomic_flag() noexcept;
Effects: Initializes *this to the clear state.
bool atomic_flag_test(const volatile atomic_flag* object) noexcept; bool atomic_flag_test(const atomic_flag* object) noexcept; bool atomic_flag_test_explicit(const volatile atomic_flag* object, memory_order order) noexcept; 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; bool atomic_flag::test(memory_order order = memory_order::seq_cst) const noexcept;
For atomic_flag_test, let order be memory_order​::​seq_cst.
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Memory is affected according to the value of order.
Returns: Atomically returns the value pointed to by object or this.
bool atomic_flag_test_and_set(volatile atomic_flag* object) noexcept; 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; 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; bool atomic_flag::test_and_set(memory_order order = memory_order::seq_cst) noexcept;
Effects: Atomically sets the value pointed to by object or by this to true.
Memory is affected according to the value of order.
These operations are atomic read-modify-write operations ([intro.multithread]).
Returns: Atomically, the value of the object immediately before the effects.
void atomic_flag_clear(volatile atomic_flag* object) noexcept; void atomic_flag_clear(atomic_flag* object) noexcept; void atomic_flag_clear_explicit(volatile atomic_flag* object, memory_order order) noexcept; 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; void atomic_flag::clear(memory_order order = memory_order::seq_cst) noexcept;
Preconditions: order is memory_order​::​relaxed, memory_order​::​release, or memory_order​::​seq_cst.
Effects: Atomically sets the value pointed to by object or by this to false.
Memory is affected according to the value of order.
void atomic_flag_wait(const volatile atomic_flag* object, bool old) noexcept; 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; 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; void atomic_flag::wait(bool old, memory_order order = memory_order::seq_cst) const noexcept;
For atomic_flag_wait, let order be memory_order​::​seq_cst.
Let flag be object for the non-member functions and this for the member functions.
Preconditions: order is memory_order​::​relaxed, memory_order​::​consume, memory_order​::​ac-
quire
, or memory_order​::​seq_cst.
Effects: Repeatedly performs the following steps, in order:
  • Evaluates flag->test(order) != old.
  • If the result of that evaluation is true, returns.
  • Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.
Remarks: This function is an atomic waiting operation ([atomics.wait]).
void atomic_flag_notify_one(volatile atomic_flag* object) noexcept; void atomic_flag_notify_one(atomic_flag* object) noexcept; void atomic_flag::notify_one() volatile noexcept; void atomic_flag::notify_one() noexcept;
Effects: Unblocks the execution of at least one atomic waiting operation that is eligible to be unblocked ([atomics.wait]) by this call, if any such atomic waiting operations exist.
Remarks: This function is an atomic notifying operation ([atomics.wait]).
void atomic_flag_notify_all(volatile atomic_flag* object) noexcept; void atomic_flag_notify_all(atomic_flag* object) noexcept; void atomic_flag::notify_all() volatile noexcept; void atomic_flag::notify_all() noexcept;
Effects: Unblocks the execution of all atomic waiting operations that are eligible to be unblocked ([atomics.wait]) by this call.
Remarks: This function is an atomic notifying operation ([atomics.wait]).
#define ATOMIC_FLAG_INIT see below
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.
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.
For a complete static-duration object, that initialization shall be static.

33.5.11 Fences [atomics.fences]

This subclause introduces synchronization primitives called fences.
Fences can have acquire semantics, release semantics, or both.
A fence with acquire semantics is called an acquire fence.
A fence with release semantics is called a release fence.
A release fence A synchronizes with an acquire fence B if there exist atomic operations X and Y, both operating on some atomic object M, such that A is sequenced before X, X modifies M, Y is sequenced before B, and Y reads the value written by X or a value written by any side effect in the hypothetical release sequence X would head if it were a release operation.
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.
An atomic operation A that is a release operation on an atomic object M synchronizes with an acquire fence B if there exists some atomic operation X on M such that X is sequenced before B and reads the value written by A or a value written by any side effect in the release sequence headed by A.
extern "C" void atomic_thread_fence(memory_order order) noexcept;
Effects: Depending on the value of order, this operation:
  • has no effects, if order == memory_order​::​relaxed;
  • is an acquire fence, if order == memory_order​::​acquire or order == memory_order​::​consume;
  • is a release fence, if order == memory_order​::​release;
  • is both an acquire fence and a release fence, if order == memory_order​::​acq_rel;
  • is a sequentially consistent acquire and release fence, if order == memory_order​::​seq_cst.
extern "C" void atomic_signal_fence(memory_order order) noexcept;
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.
[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.
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.
β€” end note]

33.5.12 C compatibility [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; // see below using std::memory_order_relaxed; // see below using std::memory_order_consume; // see below using std::memory_order_acquire; // see below using std::memory_order_release; // see below using std::memory_order_acq_rel; // see below using std::memory_order_seq_cst; // see below using std::atomic_flag; // see below using std::atomic_bool; // see below using std::atomic_char; // see below using std::atomic_schar; // see below using std::atomic_uchar; // see below using std::atomic_short; // see below using std::atomic_ushort; // see below using std::atomic_int; // see below using std::atomic_uint; // see below using std::atomic_long; // see below using std::atomic_ulong; // see below using std::atomic_llong; // see below using std::atomic_ullong; // see below using std::atomic_char8_t; // see below using std::atomic_char16_t; // see below using std::atomic_char32_t; // see below using std::atomic_wchar_t; // see below using std::atomic_int8_t; // see below using std::atomic_uint8_t; // see below using std::atomic_int16_t; // see below using std::atomic_uint16_t; // see below using std::atomic_int32_t; // see below using std::atomic_uint32_t; // see below using std::atomic_int64_t; // see below using std::atomic_uint64_t; // see below using std::atomic_int_least8_t; // see below using std::atomic_uint_least8_t; // see below using std::atomic_int_least16_t; // see below using std::atomic_uint_least16_t; // see below using std::atomic_int_least32_t; // see below using std::atomic_uint_least32_t; // see below using std::atomic_int_least64_t; // see below using std::atomic_uint_least64_t; // see below using std::atomic_int_fast8_t; // see below using std::atomic_uint_fast8_t; // see below using std::atomic_int_fast16_t; // see below using std::atomic_uint_fast16_t; // see below using std::atomic_int_fast32_t; // see below using std::atomic_uint_fast32_t; // see below using std::atomic_int_fast64_t; // see below using std::atomic_uint_fast64_t; // see below using std::atomic_intptr_t; // see below using std::atomic_uintptr_t; // see below using std::atomic_size_t; // see below using std::atomic_ptrdiff_t; // see below using std::atomic_intmax_t; // see below using std::atomic_uintmax_t; // see below using std::atomic_is_lock_free; // see below using std::atomic_load; // see below using std::atomic_load_explicit; // see below using std::atomic_store; // see below using std::atomic_store_explicit; // see below using std::atomic_exchange; // see below using std::atomic_exchange_explicit; // see below using std::atomic_compare_exchange_strong; // see below using std::atomic_compare_exchange_strong_explicit; // see below using std::atomic_compare_exchange_weak; // see below using std::atomic_compare_exchange_weak_explicit; // see below using std::atomic_fetch_add; // see below using std::atomic_fetch_add_explicit; // see below using std::atomic_fetch_sub; // see below using std::atomic_fetch_sub_explicit; // see below using std::atomic_fetch_and; // see below using std::atomic_fetch_and_explicit; // see below using std::atomic_fetch_or; // see below using std::atomic_fetch_or_explicit; // see below using std::atomic_fetch_xor; // see below using std::atomic_fetch_xor_explicit; // see below using std::atomic_flag_test_and_set; // see below using std::atomic_flag_test_and_set_explicit; // see below using std::atomic_flag_clear; // see below using std::atomic_flag_clear_explicit; // see below #define ATOMIC_FLAG_INIT see below using std::atomic_thread_fence; // see below using std::atomic_signal_fence; // see below
Each using-declaration for some name A in the synopsis above makes available the same entity as std​::​A declared in <atomic>.
Each macro listed above other than _Atomic(T) is defined as in <atomic>.
It is unspecified whether <stdatomic.h> makes available any declarations in namespace std.
Each of the using-declarations for intN_t, uintN_t, intptr_t, and uintptr_t listed above is defined if and only if the implementation defines the corresponding typedef-name in [atomics.syn].
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>.
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.
The representations should be the same, and the mechanisms used to ensure atomicity and memory ordering should be compatible.

33.6 Mutual exclusion [thread.mutex]

33.6.1 General [thread.mutex.general]

Subclause [thread.mutex] provides mechanisms for mutual exclusion: mutexes, locks, and call once.
These mechanisms ease the production of race-free programs ([intro.multithread]).

33.6.2 Header <mutex> synopsis [mutex.syn]

namespace std { // [thread.mutex.class], class mutex class mutex; // [thread.mutex.recursive], class recursive_mutex class recursive_mutex; // [thread.timedmutex.class] class timed_mutex class timed_mutex; // [thread.timedmutex.recursive], class recursive_timed_mutex class recursive_timed_mutex; struct defer_lock_t { explicit defer_lock_t() = default; }; struct try_to_lock_t { explicit try_to_lock_t() = default; }; struct adopt_lock_t { explicit adopt_lock_t() = default; }; inline constexpr defer_lock_t defer_lock { }; inline constexpr try_to_lock_t try_to_lock { }; inline constexpr adopt_lock_t adopt_lock { }; // [thread.lock], locks template<class Mutex> class lock_guard; template<class... MutexTypes> class scoped_lock; template<class Mutex> class unique_lock; template<class Mutex> void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept; // [thread.lock.algorithm], generic locking algorithms template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...); template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...); struct once_flag; template<class Callable, class... Args> void call_once(once_flag& flag, Callable&& func, Args&&... args); }

33.6.3 Header <shared_mutex> synopsis [shared.mutex.syn]

namespace std { // [thread.sharedmutex.class], class shared_mutex class shared_mutex; // [thread.sharedtimedmutex.class], class shared_timed_mutex class shared_timed_mutex; // [thread.lock.shared], class template shared_lock template<class Mutex> class shared_lock; template<class Mutex> void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept; }

33.6.4 Mutex requirements [thread.mutex.requirements]

33.6.4.1 In general [thread.mutex.requirements.general]

A mutex object facilitates protection against data races and allows safe synchronization of data between execution agents.
An execution agent owns a mutex from the time it successfully calls one of the lock functions until it calls unlock.
Mutexes can be either recursive or non-recursive, and can grant simultaneous ownership to one or many execution agents.
Both recursive and non-recursive mutexes are supplied.

33.6.4.2 Mutex types [thread.mutex.requirements.mutex]

33.6.4.2.1 General [thread.mutex.requirements.mutex.general]

The mutex types are the standard library types mutex, recursive_mutex, timed_mutex, recursive_timed_mutex, shared_mutex, and shared_timed_mutex.
They meet the requirements set out in [thread.mutex.requirements.mutex].
In this description, m denotes an object of a mutex type.
[Note 1: 
The mutex types meet the Cpp17Lockable requirements ([thread.req.lockable.req]).
β€” end note]
The mutex types meet Cpp17DefaultConstructible and Cpp17Destructible.
If initialization of an object of a mutex type fails, an exception of type system_error is thrown.
The mutex types are neither copyable nor movable.
The error conditions for error codes, if any, reported by member functions of the mutex types are as follows:
  • resource_unavailable_try_again β€” if any native handle type manipulated is not available.
  • operation_not_permitted β€” if the thread does not have the privilege to perform the operation.
  • invalid_argument β€” if any native handle type manipulated as part of mutex construction is incorrect.
The implementation provides lock and unlock operations, as described below.
For purposes of determining the existence of a data race, these behave as atomic operations ([intro.multithread]).
The lock and unlock operations on a single mutex appears to occur in a single total order.
[Note 2: 
This can be viewed as the modification order of the mutex.
β€” end note]
[Note 3: 
Construction and destruction of an object of a mutex type need not be thread-safe; other synchronization can be used to ensure that mutex objects are initialized and visible to other threads.
β€” end note]
The expression m.lock() is well-formed and has the following semantics:
Preconditions: If m is of type mutex, timed_mutex, shared_mutex, or shared_timed_mutex, the calling thread does not own the mutex.
Effects: Blocks the calling thread until ownership of the mutex can be obtained for the calling thread.
Synchronization: Prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.
Postconditions: The calling thread owns the mutex.
Return type: void.
Throws: system_error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_not_permitted β€” if the thread does not have the privilege to perform the operation.
  • resource_deadlock_would_occur β€” if the implementation detects that a deadlock would occur.
The expression m.try_lock() is well-formed and has the following semantics:
Preconditions: If m is of type mutex, timed_mutex, shared_mutex, or shared_timed_mutex, the calling thread does not own the mutex.
Effects: Attempts to obtain ownership of the mutex for the calling thread without blocking.
If ownership is not obtained, there is no effect and try_lock() immediately returns.
An implementation may fail to obtain the lock even if it is not held by any other thread.
[Note 4: 
This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange ([atomics]).
β€” end note]
An implementation should ensure that try_lock() does not consistently return false in the absence of contending mutex acquisitions.
Synchronization: If try_lock() returns true, prior unlock() operations on the same object synchronize with this operation.
[Note 5: 
Since lock() does not synchronize with a failed subsequent try_lock(), the visibility rules are weak enough that little would be known about the state after a failure, even in the absence of spurious failures.
β€” end note]
Return type: bool.
Returns: true if ownership was obtained, otherwise false.
Throws: Nothing.
The expression m.unlock() is well-formed and has the following semantics:
Preconditions: The calling thread owns the mutex.
Effects: Releases the calling thread's ownership of the mutex.
Return type: void.
Synchronization: This operation synchronizes with subsequent lock operations that obtain ownership on the same object.
Throws: Nothing.

33.6.4.2.2 Class mutex [thread.mutex.class]

namespace std { class mutex { public: constexpr mutex() noexcept; ~mutex(); mutex(const mutex&) = delete; mutex& operator=(const mutex&) = delete; void lock(); bool try_lock(); void unlock(); using native_handle_type = implementation-defined; // see [thread.req.native] native_handle_type native_handle(); // see [thread.req.native] }; }
The class mutex provides a non-recursive mutex with exclusive ownership semantics.
If one thread owns a mutex object, attempts by another thread to acquire ownership of that object will fail (for try_lock()) or block (for lock()) until the owning thread has released ownership with a call to unlock().
[Note 1: 
After a thread A has called unlock(), releasing a mutex, it is possible for another thread B to lock the same mutex, observe that it is no longer in use, unlock it, and destroy it, before thread A appears to have returned from its unlock call.
Implementations are required to handle such scenarios correctly, as long as thread A doesn't access the mutex after the unlock call returns.
These cases typically occur when a reference-counted object contains a mutex that is used to protect the reference count.
β€” end note]
The class mutex meets all of the mutex requirements ([thread.mutex.requirements]).
It is a standard-layout class ([class.prop]).
[Note 2: 
A program can deadlock if the thread that owns a mutex object calls lock() on that object.
If the implementation can detect the deadlock, a resource_deadlock_would_occur error condition might be observed.
β€” end note]
The behavior of a program is undefined if it destroys a mutex object owned by any thread or a thread terminates while owning a mutex object.

33.6.4.2.3 Class recursive_mutex [thread.mutex.recursive]

namespace std { class recursive_mutex { public: recursive_mutex(); ~recursive_mutex(); recursive_mutex(const recursive_mutex&) = delete; recursive_mutex& operator=(const recursive_mutex&) = delete; void lock(); bool try_lock() noexcept; void unlock(); using native_handle_type = implementation-defined; // see [thread.req.native] native_handle_type native_handle(); // see [thread.req.native] }; }
The class recursive_mutex provides a recursive mutex with exclusive ownership semantics.
If one thread owns a recursive_mutex object, attempts by another thread to acquire ownership of that object will fail (for try_lock()) or block (for lock()) until the first thread has completely released ownership.
The class recursive_mutex meets all of the mutex requirements ([thread.mutex.requirements]).
It is a standard-layout class ([class.prop]).
A thread that owns a recursive_mutex object may acquire additional levels of ownership by calling lock() or try_lock() on that object.
It is unspecified how many levels of ownership may be acquired by a single thread.
If a thread has already acquired the maximum level of ownership for a recursive_mutex object, additional calls to try_lock() fail, and additional calls to lock() throw an exception of type system_error.
A thread shall call unlock() once for each level of ownership acquired by calls to lock() and try_lock().
Only when all levels of ownership have been released may ownership be acquired by another thread.
The behavior of a program is undefined if:
  • it destroys a recursive_mutex object owned by any thread or
  • a thread terminates while owning a recursive_mutex object.

33.6.4.3 Timed mutex types [thread.timedmutex.requirements]

33.6.4.3.1 General [thread.timedmutex.requirements.general]

The timed mutex types are the standard library types timed_mutex, recursive_timed_mutex, and shared_timed_mutex.
They meet the requirements set out below.
In this description, m denotes an object of a mutex type, rel_time denotes an object of an instantiation of duration, and abs_time denotes an object of an instantiation of time_point.
[Note 1: 
The timed mutex types meet the Cpp17TimedLockable requirements ([thread.req.lockable.timed]).
β€” end note]
The expression m.try_lock_for(rel_time) is well-formed and has the following semantics:
Preconditions: If m is of type timed_mutex or shared_timed_mutex, the calling thread does not own the mutex.
Effects: The function attempts to obtain ownership of the mutex within the relative timeout ([thread.req.timing]) specified by rel_time.
If the time specified by rel_time is less than or equal to rel_time.zero(), the function attempts to obtain ownership without blocking (as if by calling try_lock()).
The function returns within the timeout specified by rel_time only if it has obtained ownership of the mutex object.
[Note 2: 
As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so.
β€” end note]
Synchronization: If try_lock_for() returns true, prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.
Return type: bool.
Returns: true if ownership was obtained, otherwise false.
Throws: Timeout-related exceptions ([thread.req.timing]).
The expression m.try_lock_until(abs_time) is well-formed and has the following semantics:
Preconditions: If m is of type timed_mutex or shared_timed_mutex, the calling thread does not own the mutex.
Effects: The function attempts to obtain ownership of the mutex.
If abs_time has already passed, the function attempts to obtain ownership without blocking (as if by calling try_lock()).
The function returns before the absolute timeout ([thread.req.timing]) specified by abs_time only if it has obtained ownership of the mutex object.
[Note 3: 
As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so.
β€” end note]
Synchronization: If try_lock_until() returns true, prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.
Return type: bool.
Returns: true if ownership was obtained, otherwise false.
Throws: Timeout-related exceptions ([thread.req.timing]).

33.6.4.3.2 Class timed_mutex [thread.timedmutex.class]

namespace std { class timed_mutex { public: timed_mutex(); ~timed_mutex(); timed_mutex(const timed_mutex&) = delete; timed_mutex& operator=(const timed_mutex&) = delete; void lock(); // blocking bool try_lock(); template<class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); using native_handle_type = implementation-defined; // see [thread.req.native] native_handle_type native_handle(); // see [thread.req.native] }; }
The class timed_mutex provides a non-recursive mutex with exclusive ownership semantics.
If one thread owns a timed_mutex object, attempts by another thread to acquire ownership of that object will fail (for try_lock()) or block (for lock(), try_lock_for(), and try_lock_until()) until the owning thread has released ownership with a call to unlock() or the call to try_lock_for() or try_lock_until() times out (having failed to obtain ownership).
The class timed_mutex meets all of the timed mutex requirements ([thread.timedmutex.requirements]).
It is a standard-layout class ([class.prop]).
The behavior of a program is undefined if:
  • it destroys a timed_mutex object owned by any thread,
  • a thread that owns a timed_mutex object calls lock(), try_lock(), try_lock_for(), or try_lock_until() on that object, or
  • a thread terminates while owning a timed_mutex object.

33.6.4.3.3 Class recursive_timed_mutex [thread.timedmutex.recursive]

namespace std { class recursive_timed_mutex { public: recursive_timed_mutex(); ~recursive_timed_mutex(); recursive_timed_mutex(const recursive_timed_mutex&) = delete; recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; void lock(); // blocking bool try_lock() noexcept; template<class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); using native_handle_type = implementation-defined; // see [thread.req.native] native_handle_type native_handle(); // see [thread.req.native] }; }
The class recursive_timed_mutex provides a recursive mutex with exclusive ownership semantics.
If one thread owns a recursive_timed_mutex object, attempts by another thread to acquire ownership of that object will fail (for try_lock()) or block (for lock(), try_lock_for(), and try_lock_until()) until the owning thread has completely released ownership or the call to try_lock_for() or try_lock_until() times out (having failed to obtain ownership).
The class recursive_timed_mutex meets all of the timed mutex requirements ([thread.timedmutex.requirements]).
It is a standard-layout class ([class.prop]).
A thread that owns a recursive_timed_mutex object may acquire additional levels of ownership by calling lock(), try_lock(), try_lock_for(), or try_lock_until() on that object.
It is unspecified how many levels of ownership may be acquired by a single thread.
If a thread has already acquired the maximum level of ownership for a recursive_timed_mutex object, additional calls to try_lock(), try_lock_for(), or try_lock_until() fail, and additional calls to lock() throw an exception of type system_error.
A thread shall call unlock() once for each level of ownership acquired by calls to lock(), try_lock(), try_lock_for(), and try_lock_until().
Only when all levels of ownership have been released may ownership of the object be acquired by another thread.
The behavior of a program is undefined if:
  • it destroys a recursive_timed_mutex object owned by any thread, or
  • a thread terminates while owning a recursive_timed_mutex object.

33.6.4.4 Shared mutex types [thread.sharedmutex.requirements]

33.6.4.4.1 General [thread.sharedmutex.requirements.general]

The standard library types shared_mutex and shared_timed_mutex are shared mutex types.
Shared mutex types meet the requirements of mutex types ([thread.mutex.requirements.mutex]) and additionally meet the requirements set out below.
In this description, m denotes an object of a shared mutex type.
[Note 1: 
The shared mutex types meet the Cpp17SharedLockable requirements ([thread.req.lockable.shared]).
β€” end note]
In addition to the exclusive lock ownership mode specified in [thread.mutex.requirements.mutex], shared mutex types provide a shared lock ownership mode.
Multiple execution agents can simultaneously hold a shared lock ownership of a shared mutex type.
But no execution agent holds a shared lock while another execution agent holds an exclusive lock on the same shared mutex type, and vice-versa.
The maximum number of execution agents which can share a shared lock on a single shared mutex type is unspecified, but is at least 10000.
If more than the maximum number of execution agents attempt to obtain a shared lock, the excess execution agents block until the number of shared locks are reduced below the maximum amount by other execution agents releasing their shared lock.
The expression m.lock_shared() is well-formed and has the following semantics:
Preconditions: The calling thread has no ownership of the mutex.
Effects: Blocks the calling thread until shared ownership of the mutex can be obtained for the calling thread.
If an exception is thrown then a shared lock has not been acquired for the current thread.
Synchronization: Prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.
Postconditions: The calling thread has a shared lock on the mutex.
Return type: void.
Throws: system_error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_not_permitted β€” if the thread does not have the privilege to perform the operation.
  • resource_deadlock_would_occur β€” if the implementation detects that a deadlock would occur.
The expression m.unlock_shared() is well-formed and has the following semantics:
Preconditions: The calling thread holds a shared lock on the mutex.
Effects: Releases a shared lock on the mutex held by the calling thread.
Return type: void.
Synchronization: This operation synchronizes with subsequent lock() operations that obtain ownership on the same object.
Throws: Nothing.
The expression m.try_lock_shared() is well-formed and has the following semantics:
Preconditions: The calling thread has no ownership of the mutex.
Effects: Attempts to obtain shared ownership of the mutex for the calling thread without blocking.
If shared ownership is not obtained, there is no effect and try_lock_shared() immediately returns.
An implementation may fail to obtain the lock even if it is not held by any other thread.
Synchronization: If try_lock_shared() returns true, prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.
Return type: bool.
Returns: true if the shared lock was acquired, otherwise false.
Throws: Nothing.

33.6.4.4.2 Class shared_mutex [thread.sharedmutex.class]

namespace std { class shared_mutex { public: shared_mutex(); ~shared_mutex(); shared_mutex(const shared_mutex&) = delete; shared_mutex& operator=(const shared_mutex&) = delete; // exclusive ownership void lock(); // blocking bool try_lock(); void unlock(); // shared ownership void lock_shared(); // blocking bool try_lock_shared(); void unlock_shared(); using native_handle_type = implementation-defined; // see [thread.req.native] native_handle_type native_handle(); // see [thread.req.native] }; }
The class shared_mutex provides a non-recursive mutex with shared ownership semantics.
The class shared_mutex meets all of the shared mutex requirements ([thread.sharedmutex.requirements]).
It is a standard-layout class ([class.prop]).
The behavior of a program is undefined if:
  • it destroys a shared_mutex object owned by any thread,
  • a thread attempts to recursively gain any ownership of a shared_mutex, or
  • a thread terminates while possessing any ownership of a shared_mutex.
shared_mutex may be a synonym for shared_timed_mutex.

33.6.4.5 Shared timed mutex types [thread.sharedtimedmutex.requirements]

33.6.4.5.1 General [thread.sharedtimedmutex.requirements.general]

The standard library type shared_timed_mutex is a shared timed mutex type.
Shared timed mutex types meet the requirements of timed mutex types ([thread.timedmutex.requirements]), shared mutex types ([thread.sharedmutex.requirements]), and additionally meet the requirements set out below.
In this description, m denotes an object of a shared timed mutex type, rel_time denotes an object of an instantiation of duration ([time.duration]), and abs_time denotes an object of an instantiation of time_point.
[Note 1: 
The shared timed mutex types meet the Cpp17SharedTimedLockable requirements ([thread.req.lockable.shared.timed]).
β€” end note]
The expression m.try_lock_shared_for(rel_time) is well-formed and has the following semantics:
Preconditions: The calling thread has no ownership of the mutex.
Effects: Attempts to obtain shared lock ownership for the calling thread within the relative timeout ([thread.req.timing]) specified by rel_time.
If the time specified by rel_time is less than or equal to rel_time.zero(), the function attempts to obtain ownership without blocking (as if by calling try_lock_shared()).
The function returns within the timeout specified by rel_time only if it has obtained shared ownership of the mutex object.
[Note 2: 
As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so.
β€” end note]
If an exception is thrown then a shared lock has not been acquired for the current thread.
Synchronization: If try_lock_shared_for() returns true, prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.
Return type: bool.
Returns: true if the shared lock was acquired, otherwise false.
Throws: Timeout-related exceptions ([thread.req.timing]).
The expression m.try_lock_shared_until(abs_time) is well-formed and has the following semantics:
Preconditions: The calling thread has no ownership of the mutex.
Effects: The function attempts to obtain shared ownership of the mutex.
If abs_time has already passed, the function attempts to obtain shared ownership without blocking (as if by calling try_lock_shared()).
The function returns before the absolute timeout ([thread.req.timing]) specified by abs_time only if it has obtained shared ownership of the mutex object.
[Note 3: 
As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so.
β€” end note]
If an exception is thrown then a shared lock has not been acquired for the current thread.
Synchronization: If try_lock_shared_until() returns true, prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.
Return type: bool.
Returns: true if the shared lock was acquired, otherwise false.
Throws: Timeout-related exceptions ([thread.req.timing]).

33.6.4.5.2 Class shared_timed_mutex [thread.sharedtimedmutex.class]

namespace std { class shared_timed_mutex { public: shared_timed_mutex(); ~shared_timed_mutex(); shared_timed_mutex(const shared_timed_mutex&) = delete; shared_timed_mutex& operator=(const shared_timed_mutex&) = delete; // exclusive ownership void lock(); // blocking bool try_lock(); template<class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // shared ownership void lock_shared(); // blocking bool try_lock_shared(); template<class Rep, class Period> bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration> bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock_shared(); }; }
The class shared_timed_mutex provides a non-recursive mutex with shared ownership semantics.
The class shared_timed_mutex meets all of the shared timed mutex requirements ([thread.sharedtimedmutex.requirements]).
It is a standard-layout class ([class.prop]).
The behavior of a program is undefined if:
  • it destroys a shared_timed_mutex object owned by any thread,
  • a thread attempts to recursively gain any ownership of a shared_timed_mutex, or
  • a thread terminates while possessing any ownership of a shared_timed_mutex.

33.6.5 Locks [thread.lock]

33.6.5.1 General [thread.lock.general]

A lock is an object that holds a reference to a lockable object and may unlock the lockable object during the lock's destruction (such as when leaving block scope).
An execution agent may use a lock to aid in managing ownership of a lockable object in an exception safe manner.
A lock is said to own a lockable object if it is currently managing the ownership of that lockable object for an execution agent.
A lock does not manage the lifetime of the lockable object it references.
[Note 1: 
Locks are intended to ease the burden of unlocking the lockable object under both normal and exceptional circumstances.
β€” end note]
Some lock constructors take tag types which describe what should be done with the lockable object during the lock's construction.
namespace std { struct defer_lock_t { }; // do not acquire ownership of the mutex struct try_to_lock_t { }; // try to acquire ownership of the mutex // without blocking struct adopt_lock_t { }; // assume the calling thread has already // obtained mutex ownership and manage it inline constexpr defer_lock_t defer_lock { }; inline constexpr try_to_lock_t try_to_lock { }; inline constexpr adopt_lock_t adopt_lock { }; }

33.6.5.2 Class template lock_guard [thread.lock.guard]

namespace std { template<class Mutex> class lock_guard { public: using mutex_type = Mutex; explicit lock_guard(mutex_type& m); lock_guard(mutex_type& m, adopt_lock_t); ~lock_guard(); lock_guard(const lo