%!TEX root = std.tex \rSec0[thread]{Concurrency support library} \rSec1[thread.general]{General} \pnum The following subclauses describe components to create and manage threads\iref{intro.multithread}, perform mutual exclusion, and communicate conditions and values between threads, as summarized in \tref{thread.summary}. \begin{libsumtab}{Concurrency support library summary}{thread.summary} \ref{thread.req} & Requirements & \\ \rowsep \ref{thread.stoptoken}& Stop tokens & \tcode{} \\ \rowsep \ref{thread.threads} & Threads & \tcode{} \\ \rowsep \ref{atomics} & Atomic operations & \tcode{}, \tcode{} \\ \rowsep \ref{thread.mutex} & Mutual exclusion & \tcode{}, \tcode{} \\ \rowsep \ref{thread.condition}& Condition variables & \tcode{} \\ \rowsep \ref{thread.sema} & Semaphores & \tcode{} \\ \rowsep \ref{thread.coord} & Coordination types & \tcode{}, \tcode{} \\ \rowsep \ref{futures} & Futures & \tcode{} \\ \rowsep \ref{saferecl} & Safe reclamation & \tcode{}, \tcode{} \\ \end{libsumtab} \rSec1[thread.req]{Requirements} \rSec2[thread.req.paramname]{Template parameter names} \pnum Throughout this Clause, the names of template parameters are used to express type requirements. \tcode{Predicate} is a function object type\iref{function.objects}. Let \tcode{pred} denote an lvalue of type \tcode{Predicate}. Then the expression \tcode{pred()} shall be well-formed and the type \tcode{decltype(pred())} shall model \exposconcept{boolean-testable}\iref{concept.booleantestable}. The return value of \tcode{pred()}, converted to \tcode{bool}, yields \tcode{true} if the corresponding test condition is satisfied, and \tcode{false} otherwise. If a template parameter is named \tcode{Clock}, the corresponding template argument shall be a type \tcode{C} that meets the \oldconcept{Clock} requirements\iref{time.clock.req}; the program is ill-formed if \tcode{is_clock_v} is \tcode{false}. \rSec2[thread.req.exception]{Exceptions} \pnum Some functions described in this Clause are specified to throw exceptions of type \tcode{system_error}\iref{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~\ref{res.on.exception.handling}. \begin{example} Consider a function in this Clause that is specified to throw exceptions of type \tcode{system_error} and specifies error conditions that include \tcode{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 \tcode{errno} of \tcode{EPERM} is reported by a POSIX API call used by the implementation. Since POSIX specifies an \tcode{errno} of \tcode{EPERM} when ``the caller does not have the privilege to perform the operation'', the implementation maps \tcode{EPERM} to an \tcode{error_condition} of \tcode{operation_not_permitted}\iref{syserr} and an exception of type \tcode{system_error} is thrown. \end{example} \pnum The \tcode{error_code} reported by such an exception's \tcode{code()} member function compares equal to one of the conditions specified in the function's error condition element. \rSec2[thread.req.native]{Native handles} \pnum Several classes described in this Clause have members \tcode{native_handle_type} and \tcode{native_handle}. The presence of these members and their semantics is \impldef{presence and meaning of \tcode{native_handle_type} and \tcode{native_handle}}. \begin{note} 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} \rSec2[thread.req.timing]{Timing specifications} \pnum Several functions described in this Clause take an argument to specify a timeout. These timeouts are specified as either a \tcode{duration} or a \tcode{time_point} type as specified in~\ref{time}. \pnum 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 $D_i$. Ideally, this delay would be zero. Further, any contention for processor and memory resources induces a ``quality of management'' delay, expressed as duration $D_m$. The delay durations may vary from timeout to timeout, but in all cases shorter is better. \pnum The functions whose names end in \tcode{_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. \begin{footnote} Implementations for which standard time units are meaningful will typically have a steady clock within their hardware implementation. \end{footnote} Given a duration argument $D_t$, the real-time duration of the timeout is $D_t + D_i + D_m$. \pnum The functions whose names end in \tcode{_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 $C_t$, the clock time point of the return from timeout should be $C_t + D_i + D_m$ when the clock is not adjusted during the timeout. If the clock is adjusted to the time $C_a$ during the timeout, the behavior should be as follows: \begin{itemize} \item If $C_a > C_t$, the waiting function should wake as soon as possible, i.e., $C_a + D_i + D_m$, since the timeout is already satisfied. This specification may result in the total duration of the wait decreasing when measured against a steady clock. \item If $C_a \leq C_t$, the waiting function should not time out until \tcode{Clock::now()} returns a time $C_n \geq C_t$, i.e., waking at $C_t + D_i + D_m$. \begin{note} 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} \end{itemize} 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 $C_t$ and the time point of the call to the \tcode{_until} function. \recommended Implementations should decrease the duration of the wait when the clock is adjusted forwards. \pnum \begin{note} 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} \pnum 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 \term{native resolution}. \pnum Implementation-provided clocks that are used for these functions meet the \oldconcept{TrivialClock} requirements\iref{time.clock.req}. \pnum 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 \term{timeout-related exceptions}. \begin{note} Instantiations of clock, time point and duration types supplied by the implementation as specified in~\ref{time.clock} do not throw exceptions. \end{note} \rSec2[thread.req.lockable]{Requirements for \oldconcept{Lockable} types} \rSec3[thread.req.lockable.general]{In general} \pnum An \defn{execution agent} is an entity such as a thread that may perform work in parallel with other execution agents. \begin{note} 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. \pnum \begin{note} 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} \pnum The standard library templates \tcode{unique_lock}\iref{thread.lock.unique}, \tcode{shared_lock}\iref{thread.lock.shared}, \tcode{scoped_lock}\iref{thread.lock.scoped}, \tcode{lock_guard}\iref{thread.lock.guard}, \tcode{lock}, \tcode{try_lock}\iref{thread.lock.algorithm}, and \tcode{condition_variable_any}\iref{thread.condition.condvarany} all operate on user-supplied lockable objects. The \oldconcept{BasicLockable} requirements, the \oldconcept{Lockable} requirements, the \oldconcept{TimedLockable} requirements, the \oldconcept{SharedLockable} requirements, and the \oldconcept{SharedTimedLock\-able} requirements list the requirements imposed by these library types in order to acquire or release ownership of a \tcode{lock} by a given execution agent. \begin{note} The nature of any lock ownership and any synchronization it entails are not part of these requirements. \end{note} \pnum A lock on an object \tcode{m} is said to be \begin{itemize} \item a \defnadj{non-shared}{lock} if it is acquired by a call to \tcode{lock}, \tcode{try_lock}, \tcode{try_lock_for}, or \tcode{try_lock_until} on \tcode{m}, or \item a \defnadj{shared}{lock} if it is acquired by a call to \tcode{lock_shared}, \tcode{try_lock_shared}, \tcode{try_lock_shared_for}, or \tcode{try_lock_shared_until} on \tcode{m}. \end{itemize} \begin{note} Only the method of lock acquisition is considered; the nature of any lock ownership is not part of these definitions. \end{note} \rSec3[thread.req.lockable.basic]{\oldconcept{BasicLockable} requirements} \pnum A type \tcode{L} meets the \oldconcept{BasicLockable} requirements if the following expressions are well-formed and have the specified semantics (\tcode{m} denotes a value of type \tcode{L}). \begin{itemdecl} m.lock() \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \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. \end{itemdescr} \begin{itemdecl} m.unlock() \end{itemdecl} \begin{itemdescr} \pnum \expects The current execution agent holds a non-shared lock on \tcode{m}. \pnum \effects Releases a non-shared lock on \tcode{m} held by the current execution agent. \pnum \throws Nothing. \end{itemdescr} \rSec3[thread.req.lockable.req]{\oldconcept{Lockable} requirements} \pnum A type \tcode{L} meets the \oldconcept{Lockable} requirements if it meets the \oldconcept{BasicLockable} requirements and the following expressions are well-formed and have the specified semantics (\tcode{m} denotes a value of type \tcode{L}). \begin{itemdecl} m.try_lock() \end{itemdecl} \begin{itemdescr} \pnum \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. \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if the lock was acquired, otherwise \tcode{false}. \end{itemdescr} \rSec3[thread.req.lockable.timed]{\oldconcept{TimedLockable} requirements} \pnum A type \tcode{L} meets the \oldconcept{TimedLockable} requirements if it meets the \oldconcept{Lockable} requirements and the following expressions are well-formed and have the specified semantics (\tcode{m} denotes a value of type \tcode{L}, \tcode{rel_time} denotes a value of an instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes a value of an instantiation of \tcode{time_point}\iref{time.point}). \begin{itemdecl} m.try_lock_for(rel_time) \end{itemdecl} \begin{itemdescr} \pnum \effects Attempts to acquire a lock for the current execution agent within the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time}. The function will not return within the timeout specified by \tcode{rel_time} unless it has obtained a lock on \tcode{m} for the current execution agent. If an exception is thrown then a lock has not been acquired for the current execution agent. \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if the lock was acquired, otherwise \tcode{false}. \end{itemdescr} \begin{itemdecl} m.try_lock_until(abs_time) \end{itemdecl} \begin{itemdescr} \pnum \effects Attempts to acquire a lock for the current execution agent before the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}. The function will not return before the timeout specified by \tcode{abs_time} unless it has obtained a lock on \tcode{m} for the current execution agent. If an exception is thrown then a lock has not been acquired for the current execution agent. \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if the lock was acquired, otherwise \tcode{false}. \end{itemdescr} \rSec3[thread.req.lockable.shared]{\oldconcept{SharedLockable} requirements} \pnum A type \tcode{L} meets the \oldconcept{SharedLockable} requirements if the following expressions are well-formed, have the specified semantics, and the expression \tcode{m.try_lock_shared()} has type \tcode{bool} (\tcode{m} denotes a value of type \tcode{L}): \begin{itemdecl} m.lock_shared() \end{itemdecl} \begin{itemdescr} \pnum \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. \end{itemdescr} \begin{itemdecl} m.try_lock_shared() \end{itemdecl} \begin{itemdescr} \pnum \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. \pnum \returns \tcode{true} if the lock was acquired, \tcode{false} otherwise. \end{itemdescr} \begin{itemdecl} m.unlock_shared() \end{itemdecl} \begin{itemdescr} \pnum \expects The current execution agent holds a shared lock on \tcode{m}. \pnum \effects Releases a shared lock on \tcode{m} held by the current execution agent. \pnum \throws Nothing. \end{itemdescr} \rSec3[thread.req.lockable.shared.timed]{\oldconcept{SharedTimedLockable} requirements} \pnum A type \tcode{L} meets the \oldconcept{SharedTimedLockable} requirements if it meets the \oldconcept{SharedLockable} requirements, and the following expressions are well-formed, have type \tcode{bool}, and have the specified semantics (\tcode{m} denotes a value of type \tcode{L}, \tcode{rel_time} denotes a value of a specialization of \tcode{chrono::duration}, and \tcode{abs_time} denotes a value of a specialization of \tcode{chrono::time_point}). \begin{itemdecl} m.try_lock_shared_for(rel_time) \end{itemdecl} \begin{itemdescr} \pnum \effects Attempts to acquire a lock for the current execution agent within the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time}. The function will not return within the timeout specified by \tcode{rel_time} unless it has obtained a lock on \tcode{m} for the current execution agent. If an exception is thrown then a lock has not been acquired for the current execution agent. \pnum \returns \tcode{true} if the lock was acquired, \tcode{false} otherwise. \end{itemdescr} \begin{itemdecl} m.try_lock_shared_until(abs_time) \end{itemdecl} \begin{itemdescr} \pnum \effects Attempts to acquire a lock for the current execution agent before the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}. The function will not return before the timeout specified by \tcode{abs_time} unless it has obtained a lock on \tcode{m} for the current execution agent. If an exception is thrown then a lock has not been acquired for the current execution agent. \pnum \returns \tcode{true} if the lock was acquired, \tcode{false} otherwise. \end{itemdescr} \rSec1[thread.stoptoken]{Stop tokens} \rSec2[thread.stoptoken.intro]{Introduction} \pnum Subclause \ref{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 \defn{stop request}. \pnum \tcode{stop_source}, \tcode{stop_token}, and \tcode{stop_callback} implement semantics of shared ownership of a \defn{stop state}. Any \tcode{stop_source}, \tcode{stop_token}, or \tcode{stop_callback} that shares ownership of the same stop state is an \defn{associated} \tcode{stop_source}, \tcode{stop_token}, or \tcode{stop_callback}, respectively. The last remaining owner of the stop state automatically releases the resources associated with the stop state. \pnum A \tcode{stop_token} can be passed to an operation which can either \begin{itemize} \item actively poll the token to check if there has been a stop request, or \item register a callback using the \tcode{stop_callback} class template which will be called in the event that a stop request is made. \end{itemize} A stop request made via a \tcode{stop_source} will be visible to all associated \tcode{stop_token} and \tcode{stop_source} objects. Once a stop request has been made it cannot be withdrawn (a subsequent stop request has no effect). \pnum Callbacks registered via a \tcode{stop_callback} object are called when a stop request is first made by any associated \tcode{stop_source} object. \pnum Calls to the functions \tcode{request_stop}, \tcode{stop_requested}, and \tcode{stop_possible} do not introduce data races. A call to \tcode{request_stop} that returns \tcode{true} synchronizes with a call to \tcode{stop_requested} on an associated \tcode{stop_token} or \tcode{stop_source} object that returns \tcode{true}. Registration of a callback synchronizes with the invocation of that callback. \rSec2[thread.stoptoken.syn]{Header \tcode{} synopsis} \indexheader{stop_token}% \begin{codeblock} namespace std { // \ref{stoptoken}, class \tcode{stop_token} class stop_token; // \ref{stopsource}, class \tcode{stop_source} class stop_source; // no-shared-stop-state indicator struct nostopstate_t { explicit nostopstate_t() = default; }; inline constexpr nostopstate_t nostopstate{}; // \ref{stopcallback}, class template \tcode{stop_callback} template class stop_callback; } \end{codeblock} \rSec2[stoptoken]{Class \tcode{stop_token}}% \indexlibraryglobal{stop_token}% \rSec3[stoptoken.general]{General} \pnum \indexlibraryglobal{stop_token}% The class \tcode{stop_token} provides an interface for querying whether a stop request has been made (\tcode{stop_requested}) or can ever be made (\tcode{stop_possible}) using an associated \tcode{stop_source} object\iref{stopsource}. A \tcode{stop_token} can also be passed to a \tcode{stop_callback}\iref{stopcallback} constructor to register a callback to be called when a stop request has been made from an associated \tcode{stop_source}. \begin{codeblock} namespace std { class stop_token { public: // \ref{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; // \ref{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; }; } \end{codeblock} \rSec3[stoptoken.cons]{Constructors, copy, and assignment} \indexlibraryctor{stop_token}% \begin{itemdecl} stop_token() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{stop_possible()} is \tcode{false} and \tcode{stop_requested()} is \tcode{false}. \begin{note} Because the created \tcode{stop_token} object can never receive a stop request, no resources are allocated for a stop state. \end{note} \end{itemdescr} \indexlibraryctor{stop_token}% \begin{itemdecl} stop_token(const stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{*this == rhs} is \tcode{true}. \begin{note} \tcode{*this} and \tcode{rhs} share the ownership of the same stop state, if any. \end{note} \end{itemdescr} \indexlibraryctor{stop_token}% \begin{itemdecl} stop_token(stop_token&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{*this} contains the value of \tcode{rhs} prior to the start of construction and \tcode{rhs.stop_possible()} is \tcode{false}. \end{itemdescr} \indexlibrarydtor{stop_token}% \begin{itemdecl} ~stop_token(); \end{itemdecl} \begin{itemdescr} \pnum \effects Releases ownership of the stop state, if any. \end{itemdescr} \indexlibrarymember{operator=}{stop_token}% \begin{itemdecl} stop_token& operator=(const stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{stop_token(rhs).swap(*this)}. \pnum \returns \tcode{*this}. \end{itemdescr} \indexlibrarymember{operator=}{stop_token}% \begin{itemdecl} stop_token& operator=(stop_token&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{stop_token(std::move(rhs)).swap(*this)}. \pnum \returns \tcode{*this}. \end{itemdescr} \indexlibrarymember{swap}{stop_token}% \begin{itemdecl} void swap(stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Exchanges the values of \tcode{*this} and \tcode{rhs}. \end{itemdescr} \rSec3[stoptoken.mem]{Members} \indexlibrarymember{stop_requested}{stop_token}% \begin{itemdecl} [[nodiscard]] bool stop_requested() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if \tcode{*this} has ownership of a stop state that has received a stop request; otherwise, \tcode{false}. \end{itemdescr} \indexlibrarymember{stop_possible}{stop_token}% \begin{itemdecl} [[nodiscard]] bool stop_possible() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{false} if: \begin{itemize} \item \tcode{*this} does not have ownership of a stop state, or \item a stop request was not made and there are no associated \tcode{stop_source} objects; \end{itemize} otherwise, \tcode{true}. \end{itemdescr} \rSec3[stoptoken.nonmembers]{Non-member functions} \indexlibrarymember{operator==}{stop_token}% \begin{itemdecl} [[nodiscard]] bool operator==(const stop_token& lhs, const stop_token& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if \tcode{lhs} and \tcode{rhs} have ownership of the same stop state or if both \tcode{lhs} and \tcode{rhs} do not have ownership of a stop state; otherwise \tcode{false}. \end{itemdescr} \indexlibrarymember{swap}{stop_token}% \begin{itemdecl} friend void swap(stop_token& x, stop_token& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{x.swap(y)}. \end{itemdescr} \rSec2[stopsource]{Class \tcode{stop_source}}% \indexlibraryglobal{stop_source}% \rSec3[stopsource.general]{General} \pnum \indexlibraryglobal{stop_source}% The class \tcode{stop_source} implements the semantics of making a stop request. A stop request made on a \tcode{stop_source} object is visible to all associated \tcode{stop_source} and \tcode{stop_token}\iref{stoptoken} objects. Once a stop request has been made it cannot be withdrawn (a subsequent stop request has no effect). \indexlibraryglobal{nostopstate_t}% \indexlibraryglobal{nostopstate}% \begin{codeblock} namespace std { // no-shared-stop-state indicator struct nostopstate_t { explicit nostopstate_t() = default; }; inline constexpr nostopstate_t nostopstate{}; class stop_source { public: // \ref{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; // \ref{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; }; } \end{codeblock} \rSec3[stopsource.cons]{Constructors, copy, and assignment} \indexlibraryctor{stop_source}% \begin{itemdecl} stop_source(); \end{itemdecl} \begin{itemdescr} \pnum \effects Initialises \tcode{*this} to have ownership of a new stop state. \pnum \ensures \tcode{stop_possible()} is \tcode{true} and \tcode{stop_requested()} is \tcode{false}. \pnum \throws \tcode{bad_alloc} if memory cannot be allocated for the stop state. \end{itemdescr} \indexlibraryctor{stop_source}% \begin{itemdecl} explicit stop_source(nostopstate_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{stop_possible()} is \tcode{false} and \tcode{stop_requested()} is \tcode{false}. \begin{note} No resources are allocated for the state. \end{note} \end{itemdescr} \indexlibraryctor{stop_source}% \begin{itemdecl} stop_source(const stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{*this == rhs} is \tcode{true}. \begin{note} \tcode{*this} and \tcode{rhs} share the ownership of the same stop state, if any. \end{note} \end{itemdescr} \indexlibraryctor{stop_source}% \begin{itemdecl} stop_source(stop_source&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{*this} contains the value of \tcode{rhs} prior to the start of construction and \tcode{rhs.stop_possible()} is \tcode{false}. \end{itemdescr} \indexlibrarydtor{stop_source}% \begin{itemdecl} ~stop_source(); \end{itemdecl} \begin{itemdescr} \pnum \effects Releases ownership of the stop state, if any. \end{itemdescr} \indexlibrarymember{operator=}{stop_source}% \begin{itemdecl} stop_source& operator=(const stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{stop_source(rhs).swap(*this)}. \pnum \returns \tcode{*this}. \end{itemdescr} \indexlibrarymember{operator=}{stop_source}% \begin{itemdecl} stop_source& operator=(stop_source&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{stop_source(std::move(rhs)).swap(*this)}. \pnum \returns \tcode{*this}. \end{itemdescr} \indexlibrarymember{swap}{stop_source}% \begin{itemdecl} void swap(stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Exchanges the values of \tcode{*this} and \tcode{rhs}. \end{itemdescr} \rSec3[stopsource.mem]{Members} \indexlibrarymember{get_token}{stop_source sc}% \begin{itemdecl} [[nodiscard]] stop_token get_token() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{stop_token()} if \tcode{stop_possible()} is \tcode{false}; otherwise a new associated \tcode{stop_token} object. \end{itemdescr} \indexlibrarymember{stop_possible}{stop_source}% \begin{itemdecl} [[nodiscard]] bool stop_possible() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if \tcode{*this} has ownership of a stop state; otherwise, \tcode{false}. \end{itemdescr} \indexlibrarymember{stop_requested}{stop_source}% \begin{itemdecl} [[nodiscard]] bool stop_requested() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if \tcode{*this} has ownership of a stop state that has received a stop request; otherwise, \tcode{false}. \end{itemdescr} \indexlibrarymember{request_stop}{stop_source}% \begin{itemdecl} bool request_stop() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{*this} does not have ownership of a stop state, returns \tcode{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\iref{intro.races}. If the request was made, the callbacks registered by associated \tcode{stop_callback} objects are synchronously called. If an invocation of a callback exits via an exception then \tcode{terminate} is invoked\iref{except.terminate}. \begin{note} A stop request includes notifying all condition variables of type \tcode{condition_variable_any} temporarily registered during an interruptible wait\iref{thread.condvarany.intwait}. \end{note} \pnum \ensures \tcode{stop_possible()} is \tcode{false} or \tcode{stop_requested()} is \tcode{true}. \pnum \returns \tcode{true} if this call made a stop request; otherwise \tcode{false}. \end{itemdescr} \rSec3[stopsource.nonmembers]{Non-member functions} \indexlibrarymember{operator==}{stop_source}% \begin{itemdecl} [[nodiscard]] friend bool operator==(const stop_source& lhs, const stop_source& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if \tcode{lhs} and \tcode{rhs} have ownership of the same stop state or if both \tcode{lhs} and \tcode{rhs} do not have ownership of a stop state; otherwise \tcode{false}. \end{itemdescr} \indexlibrarymember{swap}{stop_source}% \begin{itemdecl} friend void swap(stop_source& x, stop_source& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{x.swap(y)}. \end{itemdescr} \rSec2[stopcallback]{Class template \tcode{stop_callback}}% \indexlibraryglobal{stop_callback}% \rSec3[stopcallback.general]{General} \pnum \indexlibraryglobal{stop_callback}% \begin{codeblock} namespace std { template class stop_callback { public: using callback_type = Callback; // \ref{stopcallback.cons}, constructors and destructor template explicit stop_callback(const stop_token& st, C&& cb) noexcept(is_nothrow_constructible_v); template explicit stop_callback(stop_token&& st, C&& cb) noexcept(is_nothrow_constructible_v); ~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; // \expos }; template stop_callback(stop_token, Callback) -> stop_callback; } \end{codeblock} \pnum \mandates \tcode{stop_callback} is instantiated with an argument for the template parameter \tcode{Callback} that satisfies both \libconcept{invocable} and \libconcept{destructible}. \pnum \expects \tcode{stop_callback} is instantiated with an argument for the template parameter \tcode{Callback} that models both \libconcept{invocable} and \libconcept{destructible}. \rSec3[stopcallback.cons]{Constructors and destructor} \indexlibraryctor{stop_callback}% \begin{itemdecl} template explicit stop_callback(const stop_token& st, C&& cb) noexcept(is_nothrow_constructible_v); template explicit stop_callback(stop_token&& st, C&& cb) noexcept(is_nothrow_constructible_v); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{Callback} and \tcode{C} satisfy \tcode{\libconcept{constructible_from}}. \pnum \expects \tcode{Callback} and \tcode{C} model \tcode{\libconcept{constructible_from}}. \pnum \effects Initializes \tcode{callback} with \tcode{std::forward(cb)}. If \tcode{st.stop_requested()} is \tcode{true}, then \tcode{std::forward(callback)()} is evaluated in the current thread before the constructor returns. Otherwise, if \tcode{st} has ownership of a stop state, acquires shared ownership of that stop state and registers the callback with that stop state such that \tcode{std::forward(callback)()} is evaluated by the first call to \tcode{request_stop()} on an associated \tcode{stop_source}. \pnum \throws Any exception thrown by the initialization of \tcode{callback}. \pnum \remarks If evaluating \tcode{std::forward(callback)()} exits via an exception, then \tcode{terminate} is invoked\iref{except.terminate}. \end{itemdescr} \indexlibrarydtor{stop_callback}% \begin{itemdecl} ~stop_callback(); \end{itemdecl} \begin{itemdescr} \pnum \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 \tcode{stop_callback}. If \tcode{callback} is concurrently executing on another thread, then the return from the invocation of \tcode{callback} strongly happens before\iref{intro.races} \tcode{callback} is destroyed. If \tcode{callback} is executing on the current thread, then the destructor does not block\iref{defns.block} waiting for the return from the invocation of \tcode{callback}. Releases ownership of the stop state, if any. \end{itemdescr} \rSec1[thread.threads]{Threads} \rSec2[thread.threads.general]{General} \pnum \ref{thread.threads} describes components that can be used to create and manage threads. \begin{note} These threads are intended to map one-to-one with operating system threads. \end{note} \rSec2[thread.syn]{Header \tcode{} synopsis} \indexheader{thread}% \begin{codeblock} #include // see \ref{compare.syn} namespace std { // \ref{thread.thread.class}, class \tcode{thread} class thread; void swap(thread& x, thread& y) noexcept; // \ref{thread.jthread.class}, class \tcode{jthread} class jthread; // \ref{thread.thread.this}, namespace \tcode{this_thread} namespace this_thread { thread::id get_id() noexcept; void yield() noexcept; template void sleep_until(const chrono::time_point& abs_time); template void sleep_for(const chrono::duration& rel_time); } } \end{codeblock} \rSec2[thread.thread.class]{Class \tcode{thread}} \rSec3[thread.thread.class.general]{General} \pnum The class \tcode{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 \tcode{thread} object uniquely represents a particular thread of execution. That representation may be transferred to other \tcode{thread} objects in such a way that no two \tcode{thread} objects simultaneously represent the same thread of execution. A thread of execution is \term{detached} when no \tcode{thread} object represents that thread. Objects of class \tcode{thread} can be in a state that does not represent a thread of execution. \begin{note} A \tcode{thread} object does not represent a thread of execution after default construction, after being moved from, or after a successful call to \tcode{detach} or \tcode{join}. \end{note} \indexlibraryglobal{thread}% \begin{codeblock} namespace std { class thread { public: // \ref{thread.thread.id}, class \tcode{thread::id} class id; using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} // construct/copy/destroy thread() noexcept; template explicit thread(F&& f, Args&&... args); ~thread(); thread(const thread&) = delete; thread(thread&&) noexcept; thread& operator=(const thread&) = delete; thread& operator=(thread&&) noexcept; // \ref{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~\ref{thread.req.native} // static members static unsigned int hardware_concurrency() noexcept; }; } \end{codeblock} \rSec3[thread.thread.id]{Class \tcode{thread::id}} \indexlibraryglobal{thread::id}% \indexlibrarymember{thread}{id}% \begin{codeblock} 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 basic_ostream& operator<<(basic_ostream& out, thread::id id); template struct formatter; // hash support template struct hash; template<> struct hash; } \end{codeblock} \pnum An object of type \tcode{thread::id} provides a unique identifier for each thread of execution and a single distinct value for all \tcode{thread} objects that do not represent a thread of execution\iref{thread.thread.class}. Each thread of execution has an associated \tcode{thread::id} object that is not equal to the \tcode{thread::id} object of any other thread of execution and that is not equal to the \tcode{thread::id} object of any \tcode{thread} object that does not represent threads of execution. \pnum The \defn{text representation} for the character type \tcode{charT} of an object of type \tcode{thread::id} is an unspecified sequence of \tcode{charT} such that, for two objects of type \tcode{thread::id} \tcode{x} and \tcode{y}, if \tcode{x == y} is \tcode{true}, the \tcode{thread::id} objects have the same text representation, and if \tcode{x != y} is \tcode{true}, the \tcode{thread::id} objects have distinct text representations. \pnum \tcode{thread::id} is a trivially copyable class\iref{class.prop}. The library may reuse the value of a \tcode{thread::id} of a terminated thread that can no longer be joined. \pnum \begin{note} Relational operators allow \tcode{thread::id} objects to be used as keys in associative containers. \end{note} \indexlibraryctor{thread::id}% \begin{itemdecl} id() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures The constructed object does not represent a thread of execution. \end{itemdescr} \indexlibrarymember{operator==}{thread::id}% \begin{itemdecl} bool operator==(thread::id x, thread::id y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} only if \tcode{x} and \tcode{y} represent the same thread of execution or neither \tcode{x} nor \tcode{y} represents a thread of execution. \end{itemdescr} \indexlibrarymember{operator<=>}{thread::id}% \begin{itemdecl} strong_ordering operator<=>(thread::id x, thread::id y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum Let $P(\tcode{x}, \tcode{y})$ be an unspecified total ordering over \tcode{thread::id} as described in \ref{alg.sorting}. \pnum \returns \tcode{strong_ordering::less} if $P(\tcode{x}, \tcode{y})$ is \tcode{true}. Otherwise, \tcode{strong_ordering::greater} if $P(\tcode{y}, \tcode{x})$ is \tcode{true}. Otherwise, \tcode{strong_ordering::equal}. \end{itemdescr} \indexlibrarymember{operator<<}{thread::id}% \begin{itemdecl} template basic_ostream& operator<< (basic_ostream& out, thread::id id); \end{itemdecl} \begin{itemdescr} \pnum \effects Inserts the text representation for \tcode{charT} of \tcode{id} into \tcode{out}. \pnum \returns \tcode{out}. \end{itemdescr} \indexlibrary{\idxcode{formatter}!specializations!\idxcode{thread::id}}% \begin{itemdecl} template struct formatter; \end{itemdecl} \begin{itemdescr} \pnum \tcode{formatter} interprets \fmtgrammarterm{format-spec} as a \fmtgrammarterm{thread-id-format-spec}. The syntax of format specifications is as follows: \begin{ncbnf} \fmtnontermdef{thread-id-format-spec}\br \opt{fill-and-align} \opt{width} \end{ncbnf} \begin{note} The productions \fmtgrammarterm{fill-and-align} and \fmtgrammarterm{width} are described in \ref{format.string.std}. \end{note} \pnum If the \fmtgrammarterm{align} option is omitted it defaults to \tcode{>}. \pnum A \tcode{thread::id} object is formatted by writing its text representation for \tcode{charT} to the output with additional padding and adjustments as specified by the format specifiers. \end{itemdescr} \indexlibrarymember{hash}{thread::id}% \begin{itemdecl} template<> struct hash; \end{itemdecl} \begin{itemdescr} \pnum The specialization is enabled\iref{unord.hash}. \end{itemdescr} \rSec3[thread.thread.constr]{Constructors} \indexlibraryctor{thread}% \begin{itemdecl} thread() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects The object does not represent a thread of execution. \pnum \ensures \tcode{get_id() == id()}. \end{itemdescr} \indexlibraryctor{thread}% \begin{itemdecl} template explicit thread(F&& f, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cvref_t} is not the same type as \tcode{thread}. \pnum \mandates The following are all \tcode{true}: \begin{itemize} \item \tcode{is_constructible_v, F>}, \item \tcode{(is_constructible_v, Args> \&\& ...)}, and \item \tcode{is_invocable_v, decay_t...>}. \end{itemize} \pnum \effects The new thread of execution executes \begin{codeblock} invoke(auto(std::forward(f)), // for \tcode{invoke}, see \ref{func.invoke} auto(std::forward(args))...) \end{codeblock} with the values produced by \tcode{auto} being materialized\iref{conv.rval} in the constructing thread. Any return value from this invocation is ignored. \begin{note} This implies that any exceptions not thrown from the invocation of the copy of \tcode{f} will be thrown in the constructing thread, not the new thread. \end{note} If the invocation of \tcode{invoke} terminates with an uncaught exception, \tcode{terminate} is invoked\iref{except.terminate}. \pnum \sync The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of \tcode{f}. \pnum \ensures \tcode{get_id() != id()}. \tcode{*this} represents the newly started thread. \pnum \throws \tcode{system_error} if unable to start the new thread. \pnum \errors \begin{itemize} \item \tcode{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. \end{itemize} \end{itemdescr} \indexlibraryctor{thread}% \begin{itemdecl} thread(thread&& x) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{x.get_id() == id()} and \tcode{get_id()} returns the value of \tcode{x.get_id()} prior to the start of construction. \end{itemdescr} \rSec3[thread.thread.destr]{Destructor} \indexlibrarydtor{thread}% \begin{itemdecl} ~thread(); \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{joinable()}, invokes \tcode{terminate}\iref{except.terminate}. Otherwise, has no effects. \begin{note} Either implicitly detaching or joining a \tcode{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} \end{itemdescr} \rSec3[thread.thread.assign]{Assignment} \indexlibrarymember{operator=}{thread}% \begin{itemdecl} thread& operator=(thread&& x) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{joinable()}, invokes \tcode{terminate}\iref{except.terminate}. Otherwise, assigns the state of \tcode{x} to \tcode{*this} and sets \tcode{x} to a default constructed state. \pnum \ensures \tcode{x.get_id() == id()} and \tcode{get_id()} returns the value of \tcode{x.get_id()} prior to the assignment. \pnum \returns \tcode{*this}. \end{itemdescr} \rSec3[thread.thread.member]{Members} \indexlibrarymember{swap}{thread}% \begin{itemdecl} void swap(thread& x) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Swaps the state of \tcode{*this} and \tcode{x}. \end{itemdescr} \indexlibrarymember{joinable}{thread}% \begin{itemdecl} bool joinable() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{get_id() != id()}. \end{itemdescr} \indexlibrarymember{join}{thread}% \begin{itemdecl} void join(); \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects Blocks until the thread represented by \tcode{*this} has completed. \pnum \sync The completion of the thread represented by \tcode{*this} synchronizes with\iref{intro.multithread} the corresponding successful \tcode{join()} return. \begin{note} Operations on \tcode{*this} are not synchronized. \end{note} \pnum \ensures The thread represented by \tcode{*this} has completed. \tcode{get_id() == id()}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{resource_deadlock_would_occur} --- if deadlock is detected or \tcode{get_id() == this_thread::\brk{}get_id()}. \item \tcode{no_such_process} --- if the thread is not valid. \item \tcode{invalid_argument} --- if the thread is not joinable. \end{itemize} \end{itemdescr} \indexlibrarymember{detach}{thread}% \begin{itemdecl} void detach(); \end{itemdecl} \begin{itemdescr} \pnum \effects The thread represented by \tcode{*this} continues execution without the calling thread blocking. When \tcode{detach()} returns, \tcode{*this} no longer represents the possibly continuing thread of execution. When the thread previously represented by \tcode{*this} ends execution, the implementation releases any owned resources. \pnum \ensures \tcode{get_id() == id()}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{no_such_process} --- if the thread is not valid. \item \tcode{invalid_argument} --- if the thread is not joinable. \end{itemize} \end{itemdescr} \indexlibrarymember{get_id}{thread}% \begin{itemdecl} id get_id() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A default constructed \tcode{id} object if \tcode{*this} does not represent a thread, otherwise \tcode{this_thread::get_id()} for the thread of execution represented by \tcode{*this}. \end{itemdescr} \rSec3[thread.thread.static]{Static members} \indexlibrarymember{hardware_concurrency}{thread}% \begin{itemdecl} unsigned hardware_concurrency() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns The number of hardware thread contexts. \begin{note} 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. \end{itemdescr} \rSec3[thread.thread.algorithm]{Specialized algorithms} \indexlibrarymember{swap}{thread}% \begin{itemdecl} void swap(thread& x, thread& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{x.swap(y)}. \end{itemdescr} \rSec2[thread.jthread.class]{Class \tcode{jthread}} \rSec3[thread.jthread.class.general]{General} \pnum The class \tcode{jthread} provides a mechanism to create a new thread of execution. The functionality is the same as for class \tcode{thread}\iref{thread.thread.class} with the additional abilities to provide a \tcode{stop_token}\iref{thread.stoptoken} to the new thread of execution, make stop requests, and automatically join. \indexlibraryglobal{jthread}% \begin{codeblock} namespace std { class jthread { public: // types using id = thread::id; using native_handle_type = thread::native_handle_type; // \ref{thread.jthread.cons}, constructors, move, and assignment jthread() noexcept; template explicit jthread(F&& f, Args&&... args); ~jthread(); jthread(const jthread&) = delete; jthread(jthread&&) noexcept; jthread& operator=(const jthread&) = delete; jthread& operator=(jthread&&) noexcept; // \ref{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~\ref{thread.req.native} // \ref{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; // \ref{thread.jthread.special}, specialized algorithms friend void swap(jthread& lhs, jthread& rhs) noexcept; // \ref{thread.jthread.static}, static members [[nodiscard]] static unsigned int hardware_concurrency() noexcept; private: stop_source ssource; // \expos }; } \end{codeblock} \rSec3[thread.jthread.cons]{Constructors, move, and assignment} \indexlibraryctor{jthread}% \begin{itemdecl} jthread() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Constructs a \tcode{jthread} object that does not represent a thread of execution. \pnum \ensures \tcode{get_id() == id()} is \tcode{true} and \tcode{ssource.stop_possible()} is \tcode{false}. \end{itemdescr} \indexlibraryctor{jthread}% \begin{itemdecl} template explicit jthread(F&& f, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cvref_t} is not the same type as \tcode{jthread}. \pnum \mandates The following are all \tcode{true}: \begin{itemize} \item \tcode{is_constructible_v, F>}, \item \tcode{(is_constructible_v, Args> \&\& ...)}, and \item \tcode{is_invocable_v, decay_t...> ||} \\ \tcode{is_invocable_v, stop_token, decay_t...>}. \end{itemize} \pnum \effects Initializes \tcode{ssource}. The new thread of execution executes \begin{codeblock} invoke(auto(std::forward(f)), get_stop_token(), // for \tcode{invoke}, see \ref{func.invoke} auto(std::forward(args))...) \end{codeblock} if that expression is well-formed, otherwise \begin{codeblock} invoke(auto(std::forward(f)), auto(std::forward(args))...) \end{codeblock} with the values produced by \tcode{auto} being materialized\iref{conv.rval} in the constructing thread. Any return value from this invocation is ignored. \begin{note} This implies that any exceptions not thrown from the invocation of the copy of \tcode{f} will be thrown in the constructing thread, not the new thread. \end{note} If the \tcode{invoke} expression exits via an exception, \tcode{terminate} is called. \pnum \sync The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of \tcode{f}. \pnum \ensures \tcode{get_id() != id()} is \tcode{true} and \tcode{ssource.stop_possible()} is \tcode{true} and \tcode{*this} represents the newly started thread. \begin{note} The calling thread can make a stop request only once, because it cannot replace this stop token. \end{note} \pnum \throws \tcode{system_error} if unable to start the new thread. \pnum \errors \begin{itemize} \item \tcode{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. \end{itemize} \end{itemdescr} \indexlibraryctor{jthread}% \begin{itemdecl} jthread(jthread&& x) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{x.get_id() == id()} and \tcode{get_id()} returns the value of \tcode{x.get_id()} prior to the start of construction. \tcode{ssource} has the value of \tcode{x.ssource} prior to the start of construction and \tcode{x.ssource.stop_possible()} is \tcode{false}. \end{itemdescr} \indexlibrarydtor{jthread}% \begin{itemdecl} ~jthread(); \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{joinable()} is \tcode{true}, calls \tcode{request_stop()} and then \tcode{join()}. \begin{note} Operations on \tcode{*this} are not synchronized. \end{note} \end{itemdescr} \indexlibrarymember{operator=}{jthread}% \begin{itemdecl} jthread& operator=(jthread&& x) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{\&x == this} is \tcode{true}, there are no effects. Otherwise, if \tcode{joinable()} is \tcode{true}, calls \tcode{request_stop()} and then \tcode{join()}, then assigns the state of \tcode{x} to \tcode{*this} and sets \tcode{x} to a default constructed state. \pnum \ensures \tcode{get_id()} returns the value of \tcode{x.get_id()} prior to the assignment. \tcode{ssource} has the value of \tcode{x.ssource} prior to the assignment. \pnum \returns \tcode{*this}. \end{itemdescr} \rSec3[thread.jthread.mem]{Members} \indexlibrarymember{swap}{jthread}% \begin{itemdecl} void swap(jthread& x) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Exchanges the values of \tcode{*this} and \tcode{x}. \end{itemdescr} \indexlibrarymember{joinable}{jthread}% \begin{itemdecl} [[nodiscard]] bool joinable() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{get_id() != id()}. \end{itemdescr} \indexlibrarymember{join}{jthread}% \begin{itemdecl} void join(); \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects Blocks until the thread represented by \tcode{*this} has completed. \pnum \sync The completion of the thread represented by \tcode{*this} synchronizes with\iref{intro.multithread} the corresponding successful \tcode{join()} return. \begin{note} Operations on \tcode{*this} are not synchronized. \end{note} \pnum \ensures The thread represented by \tcode{*this} has completed. \tcode{get_id() == id()}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{resource_deadlock_would_occur} --- if deadlock is detected or \tcode{get_id() == this_thread::\brk{}get_id()}. \item \tcode{no_such_process} --- if the thread is not valid. \item \tcode{invalid_argument} --- if the thread is not joinable. \end{itemize} \end{itemdescr} \indexlibrarymember{detach}{jthread}% \begin{itemdecl} void detach(); \end{itemdecl} \begin{itemdescr} \pnum \effects The thread represented by \tcode{*this} continues execution without the calling thread blocking. When \tcode{detach()} returns, \tcode{*this} no longer represents the possibly continuing thread of execution. When the thread previously represented by \tcode{*this} ends execution, the implementation releases any owned resources. \pnum \ensures \tcode{get_id() == id()}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{no_such_process} --- if the thread is not valid. \item \tcode{invalid_argument} --- if the thread is not joinable. \end{itemize} \end{itemdescr} \indexlibrarymember{get_id}{jthread}% \begin{itemdecl} id get_id() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A default constructed \tcode{id} object if \tcode{*this} does not represent a thread, otherwise \tcode{this_thread::get_id()} for the thread of execution represented by \tcode{*this}. \end{itemdescr} \rSec3[thread.jthread.stop]{Stop token handling} \indexlibrarymember{get_stop_source}{jthread}% \begin{itemdecl} [[nodiscard]] stop_source get_stop_source() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return ssource;} \end{itemdescr} \indexlibrarymember{get_stop_token}{jthread}% \begin{itemdecl} [[nodiscard]] stop_token get_stop_token() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return ssource.get_token();} \end{itemdescr} \indexlibrarymember{request_stop}{jthread}% \begin{itemdecl} bool request_stop() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return ssource.request_stop();} \end{itemdescr} \rSec3[thread.jthread.special]{Specialized algorithms} \indexlibrarymember{swap}{jthread}% \begin{itemdecl} friend void swap(jthread& x, jthread& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{x.swap(y)}. \end{itemdescr} \rSec3[thread.jthread.static]{Static members} \indexlibrarymember{hardware_concurrency}{jthread}% \begin{itemdecl} [[nodiscard]] static unsigned int hardware_concurrency() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{thread::hardware_concurrency()}. \end{itemdescr} \rSec2[thread.thread.this]{Namespace \tcode{this_thread}} \begin{codeblock} namespace std::this_thread { thread::id get_id() noexcept; void yield() noexcept; template void sleep_until(const chrono::time_point& abs_time); template void sleep_for(const chrono::duration& rel_time); } \end{codeblock} \indexlibrarymember{get_id}{this_thread}% \begin{itemdecl} thread::id this_thread::get_id() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns An object of type \tcode{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 \tcode{thread::id}. \end{itemdescr} \indexlibrarymember{yield}{this_thread}% \begin{itemdecl} void this_thread::yield() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Offers the implementation the opportunity to reschedule. \pnum \sync None. \end{itemdescr} \indexlibrarymember{sleep_until}{this_thread}% \begin{itemdecl} template void sleep_until(const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects Blocks the calling thread for the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}. \pnum \sync None. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \indexlibrarymember{sleep_for}{this_thread}% \begin{itemdecl} template void sleep_for(const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects Blocks the calling thread for the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time}. \pnum \sync None. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \rSec1[atomics]{Atomic operations} \rSec2[atomics.general]{General} \pnum Subclause \ref{atomics} describes components for fine-grained atomic access. This access is provided via operations on atomic objects. \rSec2[atomics.syn]{Header \tcode{} synopsis} \indexheader{atomic}% \begin{codeblock} namespace std { // \ref{atomics.order}, order and consistency enum class memory_order : @\unspecnc@; // 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 T kill_dependency(T y) noexcept; // freestanding } // \ref{atomics.lockfree}, lock-free property #define ATOMIC_BOOL_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_CHAR_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_CHAR8_T_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_CHAR16_T_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_CHAR32_T_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_WCHAR_T_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_SHORT_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_INT_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_LONG_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_LLONG_LOCK_FREE @\unspecnc@ // freestanding #define ATOMIC_POINTER_LOCK_FREE @\unspecnc@ // freestanding namespace std { // \ref{atomics.ref.generic}, class template \tcode{atomic_ref} template struct atomic_ref; // freestanding // \ref{atomics.ref.pointer}, partial specialization for pointers template struct atomic_ref; // freestanding // \ref{atomics.types.generic}, class template \tcode{atomic} template struct atomic; // freestanding // \ref{atomics.types.pointer}, partial specialization for pointers template struct atomic; // freestanding // \ref{atomics.nonmembers}, non-member functions template bool atomic_is_lock_free(const volatile atomic*) noexcept; // freestanding template bool atomic_is_lock_free(const atomic*) noexcept; // freestanding template void atomic_store(volatile atomic*, // freestanding typename atomic::value_type) noexcept; template void atomic_store(atomic*, typename atomic::value_type) noexcept; // freestanding template void atomic_store_explicit(volatile atomic*, // freestanding typename atomic::value_type, memory_order) noexcept; template void atomic_store_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template T atomic_load(const volatile atomic*) noexcept; // freestanding template T atomic_load(const atomic*) noexcept; // freestanding template T atomic_load_explicit(const volatile atomic*, memory_order) noexcept; // freestanding template T atomic_load_explicit(const atomic*, memory_order) noexcept; // freestanding template T atomic_exchange(volatile atomic*, // freestanding typename atomic::value_type) noexcept; template T atomic_exchange(atomic*, typename atomic::value_type) noexcept; // freestanding template T atomic_exchange_explicit(volatile atomic*, // freestanding typename atomic::value_type, memory_order) noexcept; template T atomic_exchange_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template bool atomic_compare_exchange_weak(volatile atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type) noexcept; template bool atomic_compare_exchange_weak(atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type) noexcept; template bool atomic_compare_exchange_strong(volatile atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type) noexcept; template bool atomic_compare_exchange_strong(atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type) noexcept; template bool atomic_compare_exchange_weak_explicit(volatile atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type, memory_order, memory_order) noexcept; template bool atomic_compare_exchange_weak_explicit(atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type, memory_order, memory_order) noexcept; template bool atomic_compare_exchange_strong_explicit(volatile atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type, memory_order, memory_order) noexcept; template bool atomic_compare_exchange_strong_explicit(atomic*, // freestanding typename atomic::value_type*, typename atomic::value_type, memory_order, memory_order) noexcept; template T atomic_fetch_add(volatile atomic*, // freestanding typename atomic::difference_type) noexcept; template T atomic_fetch_add(atomic*, typename atomic::difference_type) noexcept; // freestanding template T atomic_fetch_add_explicit(volatile atomic*, // freestanding typename atomic::difference_type, memory_order) noexcept; template T atomic_fetch_add_explicit(atomic*, typename atomic::difference_type, // freestanding memory_order) noexcept; template T atomic_fetch_sub(volatile atomic*, // freestanding typename atomic::difference_type) noexcept; template T atomic_fetch_sub(atomic*, typename atomic::difference_type) noexcept; // freestanding template T atomic_fetch_sub_explicit(volatile atomic*, // freestanding typename atomic::difference_type, memory_order) noexcept; template T atomic_fetch_sub_explicit(atomic*, typename atomic::difference_type, // freestanding memory_order) noexcept; template T atomic_fetch_and(volatile atomic*, // freestanding typename atomic::value_type) noexcept; template T atomic_fetch_and(atomic*, typename atomic::value_type) noexcept; // freestanding template T atomic_fetch_and_explicit(volatile atomic*, // freestanding typename atomic::value_type, memory_order) noexcept; template T atomic_fetch_and_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template T atomic_fetch_or(volatile atomic*, // freestanding typename atomic::value_type) noexcept; template T atomic_fetch_or(atomic*, typename atomic::value_type) noexcept; // freestanding template T atomic_fetch_or_explicit(volatile atomic*, // freestanding typename atomic::value_type, memory_order) noexcept; template T atomic_fetch_or_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template T atomic_fetch_xor(volatile atomic*, // freestanding typename atomic::value_type) noexcept; template T atomic_fetch_xor(atomic*, typename atomic::value_type) noexcept; // freestanding template T atomic_fetch_xor_explicit(volatile atomic*, // freestanding typename atomic::value_type, memory_order) noexcept; template T atomic_fetch_xor_explicit(atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template void atomic_wait(const volatile atomic*, // freestanding typename atomic::value_type) noexcept; template void atomic_wait(const atomic*, typename atomic::value_type) noexcept; // freestanding template void atomic_wait_explicit(const volatile atomic*, // freestanding typename atomic::value_type, memory_order) noexcept; template void atomic_wait_explicit(const atomic*, typename atomic::value_type, // freestanding memory_order) noexcept; template void atomic_notify_one(volatile atomic*) noexcept; // freestanding template void atomic_notify_one(atomic*) noexcept; // freestanding template void atomic_notify_all(volatile atomic*) noexcept; // freestanding template void atomic_notify_all(atomic*) noexcept; // freestanding // \ref{atomics.alias}, type aliases using atomic_bool = atomic; // freestanding using atomic_char = atomic; // freestanding using atomic_schar = atomic; // freestanding using atomic_uchar = atomic; // freestanding using atomic_short = atomic; // freestanding using atomic_ushort = atomic; // freestanding using atomic_int = atomic; // freestanding using atomic_uint = atomic; // freestanding using atomic_long = atomic; // freestanding using atomic_ulong = atomic; // freestanding using atomic_llong = atomic; // freestanding using atomic_ullong = atomic; // freestanding using atomic_char8_t = atomic; // freestanding using atomic_char16_t = atomic; // freestanding using atomic_char32_t = atomic; // freestanding using atomic_wchar_t = atomic; // freestanding using atomic_int8_t = atomic; // freestanding using atomic_uint8_t = atomic; // freestanding using atomic_int16_t = atomic; // freestanding using atomic_uint16_t = atomic; // freestanding using atomic_int32_t = atomic; // freestanding using atomic_uint32_t = atomic; // freestanding using atomic_int64_t = atomic; // freestanding using atomic_uint64_t = atomic; // freestanding using atomic_int_least8_t = atomic; // freestanding using atomic_uint_least8_t = atomic; // freestanding using atomic_int_least16_t = atomic; // freestanding using atomic_uint_least16_t = atomic; // freestanding using atomic_int_least32_t = atomic; // freestanding using atomic_uint_least32_t = atomic; // freestanding using atomic_int_least64_t = atomic; // freestanding using atomic_uint_least64_t = atomic; // freestanding using atomic_int_fast8_t = atomic; // freestanding using atomic_uint_fast8_t = atomic; // freestanding using atomic_int_fast16_t = atomic; // freestanding using atomic_uint_fast16_t = atomic; // freestanding using atomic_int_fast32_t = atomic; // freestanding using atomic_uint_fast32_t = atomic; // freestanding using atomic_int_fast64_t = atomic; // freestanding using atomic_uint_fast64_t = atomic; // freestanding using atomic_intptr_t = atomic; // freestanding using atomic_uintptr_t = atomic; // freestanding using atomic_size_t = atomic; // freestanding using atomic_ptrdiff_t = atomic; // freestanding using atomic_intmax_t = atomic; // freestanding using atomic_uintmax_t = atomic; // freestanding using atomic_signed_lock_free = @\seebelow@; using atomic_unsigned_lock_free = @\seebelow@; // \ref{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 @\seebelownc@ // freestanding // \ref{atomics.fences}, fences extern "C" void atomic_thread_fence(memory_order) noexcept; // freestanding extern "C" void atomic_signal_fence(memory_order) noexcept; // freestanding } \end{codeblock} \rSec2[atomics.alias]{Type aliases} \indexlibraryglobal{atomic_bool}% \indexlibraryglobal{atomic_char}% \indexlibraryglobal{atomic_schar}% \indexlibraryglobal{atomic_uchar}% \indexlibraryglobal{atomic_short}% \indexlibraryglobal{atomic_ushort}% \indexlibraryglobal{atomic_int}% \indexlibraryglobal{atomic_uint}% \indexlibraryglobal{atomic_long}% \indexlibraryglobal{atomic_ulong}% \indexlibraryglobal{atomic_llong}% \indexlibraryglobal{atomic_ullong}% \indexlibraryglobal{atomic_char8_t}% \indexlibraryglobal{atomic_char16_t}% \indexlibraryglobal{atomic_char32_t}% \indexlibraryglobal{atomic_wchar_t}% \indexlibraryglobal{atomic_int8_t}% \indexlibraryglobal{atomic_uint8_t}% \indexlibraryglobal{atomic_int16_t}% \indexlibraryglobal{atomic_uint16_t}% \indexlibraryglobal{atomic_int32_t}% \indexlibraryglobal{atomic_uint32_t}% \indexlibraryglobal{atomic_int64_t}% \indexlibraryglobal{atomic_uint64_t}% \indexlibraryglobal{atomic_int_least8_t}% \indexlibraryglobal{atomic_uint_least8_t}% \indexlibraryglobal{atomic_int_least16_t}% \indexlibraryglobal{atomic_uint_least16_t}% \indexlibraryglobal{atomic_int_least32_t}% \indexlibraryglobal{atomic_uint_least32_t}% \indexlibraryglobal{atomic_int_least64_t}% \indexlibraryglobal{atomic_uint_least64_t}% \indexlibraryglobal{atomic_int_fast8_t}% \indexlibraryglobal{atomic_uint_fast8_t}% \indexlibraryglobal{atomic_int_fast16_t}% \indexlibraryglobal{atomic_uint_fast16_t}% \indexlibraryglobal{atomic_int_fast32_t}% \indexlibraryglobal{atomic_uint_fast32_t}% \indexlibraryglobal{atomic_int_fast64_t}% \indexlibraryglobal{atomic_uint_fast64_t}% \indexlibraryglobal{atomic_intptr_t}% \indexlibraryglobal{atomic_uintptr_t}% \indexlibraryglobal{atomic_size_t}% \indexlibraryglobal{atomic_ptrdiff_t}% \indexlibraryglobal{atomic_intmax_t}% \indexlibraryglobal{atomic_uintmax_t}% \pnum The type aliases \tcode{atomic_int$N$_t}, \tcode{atomic_uint$N$_t}, \tcode{atomic_intptr_t}, and \tcode{atomic_uintptr_t} are defined if and only if \tcode{int$N$_t}, \tcode{uint$N$_t}, \tcode{intptr_t}, and \tcode{uintptr_t} are defined, respectively. \pnum \indexlibraryglobal{atomic_signed_lock_free}% \indexlibraryglobal{atomic_unsigned_lock_free}% The type aliases \tcode{atomic_signed_lock_free} and \tcode{atomic_unsigned_lock_free} name specializations of \tcode{atomic} whose template arguments are integral types, respectively signed and unsigned, and whose \tcode{is_always_lock_free} property is \tcode{true}. \begin{note} \indextext{implementation!freestanding}% These aliases are optional in freestanding implementations\iref{compliance}. \end{note} Implementations should choose for these aliases the integral specializations of \tcode{atomic} for which the atomic waiting and notifying operations\iref{atomics.wait} are most efficient. \rSec2[atomics.order]{Order and consistency} \indexlibraryglobal{memory_order}% \indexlibrarymember{relaxed}{memory_order}% \indexlibrarymember{consume}{memory_order}% \indexlibrarymember{acquire}{memory_order}% \indexlibrarymember{release}{memory_order}% \indexlibrarymember{acq_rel}{memory_order}% \indexlibrarymember{seq_cst}{memory_order}% \indexlibraryglobal{memory_order_relaxed}% \indexlibraryglobal{memory_order_consume}% \indexlibraryglobal{memory_order_acquire}% \indexlibraryglobal{memory_order_release}% \indexlibraryglobal{memory_order_acq_rel}% \indexlibraryglobal{memory_order_seq_cst}% \begin{codeblock} namespace std { enum class memory_order : @\unspec@ { relaxed, consume, acquire, release, acq_rel, seq_cst }; } \end{codeblock} \pnum The enumeration \tcode{memory_order} specifies the detailed regular (non-atomic) memory synchronization order as defined in \ref{intro.multithread} and may provide for operation ordering. Its enumerated values and their meanings are as follows: \begin{itemize} \item \tcode{memory_order::relaxed}: no operation orders memory. \item \tcode{memory_order::release}, \tcode{memory_order::acq_rel}, and \tcode{memory_order::seq_cst}: a store operation performs a release operation on the affected memory location. \item \tcode{memory_order::consume}: a load operation performs a consume operation on the affected memory location. \begin{note} Prefer \tcode{memory_order::acquire}, which provides stronger guarantees than \tcode{memory_order::consume}. Implementations have found it infeasible to provide performance better than that of \tcode{memory_order::acquire}. Specification revisions are under consideration. \end{note} \item \tcode{memory_order::acquire}, \tcode{memory_order::acq_rel}, and \tcode{memory_order::seq_cst}: a load operation performs an acquire operation on the affected memory location. \end{itemize} \begin{note} Atomic operations specifying \tcode{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} \pnum 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$. \pnum An atomic operation $A$ on some atomic object $M$ is \defn{coherence-ordered before} another atomic operation $B$ on $M$ if \begin{itemize} \item $A$ is a modification, and $B$ reads the value stored by $A$, or \item $A$ precedes $B$ in the modification order of $M$, or \item $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 \item there exists an atomic modification $X$ of $M$ such that $A$ is coherence-ordered before $X$ and $X$ is coherence-ordered before $B$. \end{itemize} \pnum There is a single total order $S$ on all \tcode{memory_order::seq_cst} operations, including fences, that satisfies the following constraints. First, if $A$ and $B$ are \tcode{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$: \begin{itemize} \item if $A$ and $B$ are both \tcode{memory_order::seq_cst} operations, then $A$ precedes $B$ in $S$; and \item if $A$ is a \tcode{memory_order::seq_cst} operation and $B$ happens before a \tcode{memory_order::seq_cst} fence $Y$, then $A$ precedes $Y$ in $S$; and \item if a \tcode{memory_order::seq_cst} fence $X$ happens before $A$ and $B$ is a \tcode{memory_order::seq_cst} operation, then $X$ precedes $B$ in $S$; and \item if a \tcode{memory_order::seq_cst} fence $X$ happens before $A$ and $B$ happens before a \tcode{memory_order::seq_cst} fence $Y$, then $X$ precedes $Y$ in $S$. \end{itemize} \pnum \begin{note} This definition ensures that $S$ is consistent with the modification order of any atomic object $M$. It also ensures that a \tcode{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-\tcode{memory_order::seq_cst} modification of $M$ that does not happen before any modification of $M$ that precedes $A$ in $S$. \end{note} \pnum \begin{note} We do not require that $S$ be consistent with ``happens before''\iref{intro.races}. This allows more efficient implementation of \tcode{memory_order::acquire} and \tcode{memory_order::release} on some machine architectures. It can produce surprising results when these are mixed with \tcode{memory_order::seq_cst} accesses. \end{note} \pnum \begin{note} \tcode{memory_order::seq_cst} ensures sequential consistency only for a program that is free of data races and uses exclusively \tcode{memory_order::seq_cst} atomic operations. Any use of weaker ordering will invalidate this guarantee unless extreme care is used. In many cases, \tcode{memory_order::seq_cst} atomic operations are reorderable with respect to other atomic operations performed by the same thread. \end{note} \pnum Implementations should ensure that no ``out-of-thin-air'' values are computed that circularly depend on their own computation. \begin{note} For example, with \tcode{x} and \tcode{y} initially zero, \begin{codeblock} // Thread 1: r1 = y.load(memory_order::relaxed); x.store(r1, memory_order::relaxed); \end{codeblock} \begin{codeblock} // Thread 2: r2 = x.load(memory_order::relaxed); y.store(r2, memory_order::relaxed); \end{codeblock} this recommendation discourages producing \tcode{r1 == r2 == 42}, since the store of 42 to \tcode{y} is only possible if the store to \tcode{x} stores \tcode{42}, which circularly depends on the store to \tcode{y} storing \tcode{42}. Note that without this restriction, such an execution is possible. \end{note} \pnum \begin{note} The recommendation similarly disallows \tcode{r1 == r2 == 42} in the following example, with \tcode{x} and \tcode{y} again initially zero: \begin{codeblock} // Thread 1: r1 = x.load(memory_order::relaxed); if (r1 == 42) y.store(42, memory_order::relaxed); \end{codeblock} \begin{codeblock} // Thread 2: r2 = y.load(memory_order::relaxed); if (r2 == 42) x.store(42, memory_order::relaxed); \end{codeblock} \end{note} \pnum 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. \pnum Implementations should make atomic stores visible to atomic loads within a reasonable amount of time. \indexlibraryglobal{kill_dependency}% \begin{itemdecl} template T kill_dependency(T y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects The argument does not carry a dependency to the return value\iref{intro.multithread}. \pnum \returns \tcode{y}. \end{itemdescr} \rSec2[atomics.lockfree]{Lock-free property} \indexlibraryglobal{ATOMIC_BOOL_LOCK_FREE}% \indexlibraryglobal{ATOMIC_CHAR_LOCK_FREE}% \indexlibraryglobal{ATOMIC_CHAR8_T_LOCK_FREE}% \indexlibraryglobal{ATOMIC_CHAR16_T_LOCK_FREE}% \indexlibraryglobal{ATOMIC_CHAR32_T_LOCK_FREE}% \indexlibraryglobal{ATOMIC_WCHAR_T_LOCK_FREE}% \indexlibraryglobal{ATOMIC_SHORT_LOCK_FREE}% \indexlibraryglobal{ATOMIC_INT_LOCK_FREE}% \indexlibraryglobal{ATOMIC_LONG_LOCK_FREE}% \indexlibraryglobal{ATOMIC_LLONG_LOCK_FREE}% \indexlibraryglobal{ATOMIC_POINTER_LOCK_FREE}% \indeximpldef{values of various \tcode{ATOMIC_..._LOCK_FREE} macros} \begin{codeblock} #define ATOMIC_BOOL_LOCK_FREE @\unspec@ #define ATOMIC_CHAR_LOCK_FREE @\unspec@ #define ATOMIC_CHAR8_T_LOCK_FREE @\unspec@ #define ATOMIC_CHAR16_T_LOCK_FREE @\unspec@ #define ATOMIC_CHAR32_T_LOCK_FREE @\unspec@ #define ATOMIC_WCHAR_T_LOCK_FREE @\unspec@ #define ATOMIC_SHORT_LOCK_FREE @\unspec@ #define ATOMIC_INT_LOCK_FREE @\unspec@ #define ATOMIC_LONG_LOCK_FREE @\unspec@ #define ATOMIC_LLONG_LOCK_FREE @\unspec@ #define ATOMIC_POINTER_LOCK_FREE @\unspec@ \end{codeblock} \pnum The \tcode{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 \tcode{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. \pnum On a hosted implementation\iref{compliance}, at least one signed integral specialization of the \tcode{atomic} template, along with the specialization for the corresponding unsigned type\iref{basic.fundamental}, is always lock-free. \pnum The functions \tcode{atomic::is_lock_free} and \tcode{atomic_is_lock_free}\iref{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. \pnum Atomic operations that are not lock-free are considered to potentially block\iref{intro.progress}. \pnum \recommended Operations that are lock-free should also be address-free. \begin{footnote} That is, atomic operations on the same memory location via two different addresses will communicate atomically. \end{footnote} The implementation of these operations should not depend on any per-process state. \begin{note} 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} \rSec2[atomics.wait]{Waiting and notifying} \pnum \defnx{Atomic waiting operations}{atomic!waiting operation} and \defnx{atomic notifying operations}{atomic!notifying operation} 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. \begin{note} 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} \pnum \begin{note} The following functions are atomic waiting operations: \begin{itemize} \item \tcode{atomic::wait}, \item \tcode{atomic_flag::wait}, \item \tcode{atomic_wait} and \tcode{atomic_wait_explicit}, \item \tcode{atomic_flag_wait} and \tcode{atomic_flag_wait_explicit}, and \item \tcode{atomic_ref::wait}. \end{itemize} \end{note} \pnum \begin{note} The following functions are atomic notifying operations: \begin{itemize} \item \tcode{atomic::notify_one} and \tcode{atomic::notify_all}, \item \tcode{atomic_flag::notify_one} and \tcode{atomic_flag::notify_all}, \item \tcode{atomic_notify_one} and \tcode{atomic_notify_all}, \item \tcode{atomic_flag_notify_one} and \tcode{atomic_flag_notify_all}, and \item \tcode{atomic_ref::notify_one} and \tcode{atomic_ref::notify_all}. \end{itemize} \end{note} \indextext{atomic!waiting operation!eligible to be unblocked}% \pnum A call to an atomic waiting operation on an atomic object \tcode{M} is \defn{eligible to be unblocked} by a call to an atomic notifying operation on \tcode{M} if there exist side effects \tcode{X} and \tcode{Y} on \tcode{M} such that: \begin{itemize} \item the atomic waiting operation has blocked after observing the result of \tcode{X}, \item \tcode{X} precedes \tcode{Y} in the modification order of \tcode{M}, and \item \tcode{Y} happens before the call to the atomic notifying operation. \end{itemize} \rSec2[atomics.ref.generic]{Class template \tcode{atomic_ref}} \rSec3[atomics.ref.generic.general]{General} \indexlibraryglobal{atomic_ref}% \indexlibrarymember{value_type}{atomic_ref}% \begin{codeblock} namespace std { template struct atomic_ref { private: T* ptr; // \expos public: using value_type = T; static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; 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; }; } \end{codeblock} \pnum An \tcode{atomic_ref} object applies atomic operations\iref{atomics.general} to the object referenced by \tcode{*ptr} such that, for the lifetime\iref{basic.life} of the \tcode{atomic_ref} object, the object referenced by \tcode{*ptr} is an atomic object\iref{intro.races}. \pnum The program is ill-formed if \tcode{is_trivially_copyable_v} is \tcode{false}. \pnum The lifetime\iref{basic.life} of an object referenced by \tcode{*ptr} shall exceed the lifetime of all \tcode{atomic_ref}s that reference the object. While any \tcode{atomic_ref} instances exist that reference the \tcode{*ptr} object, all accesses to that object shall exclusively occur through those \tcode{atomic_ref} instances. No subobject of the object referenced by \tcode{atomic_ref} shall be concurrently referenced by any other \tcode{atomic_ref} object. \pnum Atomic operations applied to an object through a referencing \tcode{atomic_ref} are atomic with respect to atomic operations applied through any other \tcode{atomic_ref} referencing the same object. \begin{note} Atomic operations or the \tcode{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} \rSec3[atomics.ref.ops]{Operations} \indexlibrarymember{required_alignment}{atomic_ref}% \indexlibrarymember{required_alignment}{atomic_ref}% \indexlibrarymember{required_alignment}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{required_alignment}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} static constexpr size_t required_alignment; \end{itemdecl} \begin{itemdescr} \pnum The alignment required for an object to be referenced by an atomic reference, which is at least \tcode{alignof(T)}. \pnum \begin{note} Hardware could require an object referenced by an \tcode{atomic_ref} to have stricter alignment\iref{basic.align} than other objects of type \tcode{T}. Further, whether operations on an \tcode{atomic_ref} are lock-free could depend on the alignment of the referenced object. For example, lock-free operations on \tcode{std::complex} could be supported only if aligned to \tcode{2*alignof(double)}. \end{note} \end{itemdescr} \indexlibrarymember{is_always_lock_free}{atomic_ref}% \indexlibrarymember{is_always_lock_free}{atomic_ref}% \indexlibrarymember{is_always_lock_free}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{is_always_lock_free}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} static constexpr bool is_always_lock_free; \end{itemdecl} \begin{itemdescr} \pnum The static data member \tcode{is_always_lock_free} is \tcode{true} if the \tcode{atomic_ref} type's operations are always lock-free, and \tcode{false} otherwise. \end{itemdescr} \indexlibrarymember{is_lock_free}{atomic_ref}% \indexlibrarymember{is_lock_free}{atomic_ref}% \indexlibrarymember{is_lock_free}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{is_lock_free}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} bool is_lock_free() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if operations on all objects of the type \tcode{atomic_ref} are lock-free, \tcode{false} otherwise. \end{itemdescr} \indexlibraryctor{atomic_ref}% \indexlibraryctor{atomic_ref}% \indexlibrary{\idxcode{atomic_ref<\placeholder{integral-type}>}!constructor}% \indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point-type}>}!constructor}% \begin{itemdecl} atomic_ref(T& obj); \end{itemdecl} \begin{itemdescr} \pnum \expects The referenced object is aligned to \tcode{required_alignment}. \pnum \ensures \tcode{*this} references \tcode{obj}. \pnum \throws Nothing. \end{itemdescr} \indexlibraryctor{atomic_ref}% \indexlibraryctor{atomic_ref}% \indexlibrary{\idxcode{atomic_ref<\placeholder{integral-type}>}!constructor}% \indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point-type}>}!constructor}% \begin{itemdecl} atomic_ref(const atomic_ref& ref) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{*this} references the object referenced by \tcode{ref}. \end{itemdescr} \indexlibrarymember{store}{atomic_ref}% \indexlibrarymember{store}{atomic_ref}% \indexlibrarymember{store}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{store}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} void store(T desired, memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::release}, or \tcode{memory_order::seq_cst}. \pnum \effects Atomically replaces the value referenced by \tcode{*ptr} with the value of \tcode{desired}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} \indexlibrarymember{operator=}{atomic_ref}% \indexlibrarymember{operator=}{atomic_ref}% \indexlibrarymember{operator=}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{operator=}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} T operator=(T desired) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} store(desired); return desired; \end{codeblock} \end{itemdescr} \indexlibrarymember{load}{atomic_ref}% \indexlibrarymember{load}{atomic_ref}% \indexlibrarymember{load}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{load}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} T load(memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Memory is affected according to the value of \tcode{order}. \pnum \returns Atomically returns the value referenced by \tcode{*ptr}. \end{itemdescr} \indexlibrarymember{operator \placeholder{type}}{atomic_ref}% \indexlibrarymember{operator T*}{atomic_ref}% \indexlibrarymember{operator \placeholder{integral-type}}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{operator \placeholder{floating-point-type}}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} operator T() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return load();} \end{itemdescr} \indexlibrarymember{exchange}{atomic_ref}% \indexlibrarymember{exchange}{atomic_ref}% \indexlibrarymember{exchange}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{exchange}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} T exchange(T desired, memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Atomically replaces the value referenced by \tcode{*ptr} with \tcode{desired}. Memory is affected according to the value of \tcode{order}. This operation is an atomic read-modify-write operation\iref{intro.multithread}. \pnum \returns Atomically returns the value referenced by \tcode{*ptr} immediately before the effects. \end{itemdescr} \indexlibrarymember{compare_exchange_weak}{atomic_ref}% \indexlibrarymember{compare_exchange_weak}{atomic_ref}% \indexlibrarymember{compare_exchange_weak}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{compare_exchange_weak}{atomic_ref<\placeholder{floating-point-type}>}% \indexlibrarymember{compare_exchange_strong}{atomic_ref}% \indexlibrarymember{compare_exchange_strong}{atomic_ref}% \indexlibrarymember{compare_exchange_strong}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{compare_exchange_strong}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{failure} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac\-quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Retrieves the value in \tcode{expected}. It then atomically compares the value representation of the value referenced by \tcode{*ptr} for equality with that previously retrieved from \tcode{expected}, and if \tcode{true}, replaces the value referenced by \tcode{*ptr} with that in \tcode{desired}. If and only if the comparison is \tcode{true}, memory is affected according to the value of \tcode{success}, and if the comparison is \tcode{false}, memory is affected according to the value of \tcode{failure}. When only one \tcode{memory_order} argument is supplied, the value of \tcode{success} is \tcode{order}, and the value of \tcode{failure} is \tcode{order} except that a value of \tcode{memory_order::acq_rel} shall be replaced by the value \tcode{memory_order::acquire} and a value of \tcode{memory_order::release} shall be replaced by the value \tcode{memory_order::relaxed}. If and only if the comparison is \tcode{false} then, after the atomic operation, the value in \tcode{expected} is replaced by the value read from the value referenced by \tcode{*ptr} during the atomic comparison. If the operation returns \tcode{true}, these operations are atomic read-modify-write operations\iref{intro.races} on the value referenced by \tcode{*ptr}. Otherwise, these operations are atomic load operations on that memory. \pnum \returns The result of the comparison. \pnum \remarks A weak compare-and-exchange operation may fail spuriously. That is, even when the contents of memory referred to by \tcode{expected} and \tcode{ptr} are equal, it may return \tcode{false} and store back to \tcode{expected} the same memory contents that were originally there. \begin{note} 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} \end{itemdescr} \indexlibrarymember{wait}{atomic_ref}% \begin{itemdecl} void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac- \linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Repeatedly performs the following steps, in order: \begin{itemize} \item Evaluates \tcode{load(order)} and compares its value representation for equality against that of \tcode{old}. \item If they compare unequal, returns. \item Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously. \end{itemize} \pnum \remarks This function is an atomic waiting operation\iref{atomics.wait} on atomic object \tcode{*ptr}. \end{itemdescr} \indexlibrarymember{notify_one}{atomic_ref}% \begin{itemdecl} void notify_one() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of at least one atomic waiting operation on \tcode{*ptr} that is eligible to be unblocked\iref{atomics.wait} by this call, if any such atomic waiting operations exist. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait} on atomic object \tcode{*ptr}. \end{itemdescr} \indexlibrarymember{notify_all}{atomic_ref}% \begin{itemdecl} void notify_all() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of all atomic waiting operations on \tcode{*ptr} that are eligible to be unblocked\iref{atomics.wait} by this call. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait} on atomic object \tcode{*ptr}. \end{itemdescr} \rSec3[atomics.ref.int]{Specializations for integral types} \pnum \indexlibrary{\idxcode{atomic_ref<\placeholder{integral-type}>}}% There are specializations of the \tcode{atomic_ref} class template for the integral types \tcode{char}, \tcode{signed char}, \tcode{unsigned char}, \tcode{short}, \tcode{unsigned short}, \tcode{int}, \tcode{unsigned int}, \tcode{long}, \tcode{unsigned long}, \tcode{long long}, \tcode{unsigned long long}, \keyword{char8_t}, \keyword{char16_t}, \keyword{char32_t}, \keyword{wchar_t}, and any other types needed by the typedefs in the header \libheaderref{cstdint}. For each such type \tcode{\placeholder{integral-type}}, the specialization \tcode{atomic_ref<\placeholder{integral-type}>} provides additional atomic operations appropriate to integral types. \begin{note} The specialization \tcode{atomic_ref} uses the primary template\iref{atomics.ref.generic}. \end{note} \begin{codeblock} namespace std { template<> struct atomic_ref<@\placeholder{integral-type}@> { private: @\placeholder{integral-type}@* ptr; // \expos public: using value_type = @\placeholder{integral-type}@; using difference_type = value_type; static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; bool is_lock_free() const noexcept; explicit atomic_ref(@\placeholder{integral-type}@&); atomic_ref(const atomic_ref&) noexcept; atomic_ref& operator=(const atomic_ref&) = delete; void store(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholdernc{integral-type}@ operator=(@\placeholder{integral-type}@) const noexcept; @\placeholdernc{integral-type}@ load(memory_order = memory_order::seq_cst) const noexcept; operator @\placeholdernc{integral-type}@() const noexcept; @\placeholdernc{integral-type}@ exchange(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholder{integral-type}@, memory_order, memory_order) const noexcept; bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholder{integral-type}@, memory_order, memory_order) const noexcept; bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholder{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholder{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholdernc{integral-type}@ fetch_add(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholdernc{integral-type}@ fetch_sub(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholdernc{integral-type}@ fetch_and(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholdernc{integral-type}@ fetch_or(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholdernc{integral-type}@ fetch_xor(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholdernc{integral-type}@ operator++(int) const noexcept; @\placeholdernc{integral-type}@ operator--(int) const noexcept; @\placeholdernc{integral-type}@ operator++() const noexcept; @\placeholdernc{integral-type}@ operator--() const noexcept; @\placeholdernc{integral-type}@ operator+=(@\placeholdernc{integral-type}@) const noexcept; @\placeholdernc{integral-type}@ operator-=(@\placeholdernc{integral-type}@) const noexcept; @\placeholdernc{integral-type}@ operator&=(@\placeholdernc{integral-type}@) const noexcept; @\placeholdernc{integral-type}@ operator|=(@\placeholdernc{integral-type}@) const noexcept; @\placeholdernc{integral-type}@ operator^=(@\placeholdernc{integral-type}@) const noexcept; void wait(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const noexcept; void notify_one() const noexcept; void notify_all() const noexcept; }; } \end{codeblock} \pnum Descriptions are provided below only for members that differ from the primary template. \pnum The following operations perform arithmetic computations. The correspondence among key, operator, and computation is specified in \tref{atomic.types.int.comp}. \indexlibrarymember{fetch_add}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{fetch_and}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{fetch_or}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{fetch_sub}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{fetch_xor}{atomic_ref<\placeholder{integral-type}>}% \begin{itemdecl} @\placeholdernc{integral-type}@ fetch_@\placeholdernc{key}@(@\placeholdernc{integral-type}@ operand, memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Atomically replaces the value referenced by \tcode{*ptr} with the result of the computation applied to the value referenced by \tcode{*ptr} and the given operand. Memory is affected according to the value of \tcode{order}. These operations are atomic read-modify-write operations\iref{intro.races}. \pnum \returns Atomically, the value referenced by \tcode{*ptr} immediately before the effects. \pnum \indextext{signed integer representation!two's complement}% \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. \begin{note} There are no undefined results arising from the computation. \end{note} \end{itemdescr} \indexlibrarymember{operator+=}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{operator-=}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{operator\&=}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{operator"|=}{atomic_ref<\placeholder{integral-type}>}% \indexlibrarymember{operator\caret=}{atomic_ref<\placeholder{integral-type}>}% \begin{itemdecl} @\placeholdernc{integral-type}@ operator @\placeholder{op}@=(@\placeholdernc{integral-type}@ operand) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return fetch_\placeholdernc{key}(operand) \placeholder{op} operand;} \end{itemdescr} \rSec3[atomics.ref.float]{Specializations for floating-point types} \pnum \indexlibrary{\idxcode{atomic_ref<\placeholder{floating-point-type}>}}% There are specializations of the \tcode{atomic_ref} class template for all cv-unqualified floating-point types. For each such type \tcode{\placeholder{floating-point-type}}, the specialization \tcode{atomic_ref<\placeholder{floating-\-point}>} provides additional atomic operations appropriate to floating-point types. \begin{codeblock} namespace std { template<> struct atomic_ref<@\placeholder{floating-point-type}@> { private: @\placeholder{floating-point-type}@* ptr; // \expos public: using value_type = @\placeholder{floating-point-type}@; using difference_type = value_type; static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; bool is_lock_free() const noexcept; explicit atomic_ref(@\placeholder{floating-point-type}@&); atomic_ref(const atomic_ref&) noexcept; atomic_ref& operator=(const atomic_ref&) = delete; void store(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholder{floating-point-type}@ operator=(@\placeholder{floating-point-type}@) const noexcept; @\placeholder{floating-point-type}@ load(memory_order = memory_order::seq_cst) const noexcept; operator @\placeholdernc{floating-point-type}@() const noexcept; @\placeholder{floating-point-type}@ exchange(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_weak(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order, memory_order) const noexcept; bool compare_exchange_strong(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order, memory_order) const noexcept; bool compare_exchange_weak(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) const noexcept; bool compare_exchange_strong(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholder{floating-point-type}@ fetch_add(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholder{floating-point-type}@ fetch_sub(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) const noexcept; @\placeholder{floating-point-type}@ operator+=(@\placeholder{floating-point-type}@) const noexcept; @\placeholder{floating-point-type}@ operator-=(@\placeholder{floating-point-type}@) const noexcept; void wait(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) const noexcept; void notify_one() const noexcept; void notify_all() const noexcept; }; } \end{codeblock} \pnum Descriptions are provided below only for members that differ from the primary template. \pnum The following operations perform arithmetic computations. The correspondence among key, operator, and computation is specified in \tref{atomic.types.int.comp}. \indexlibrarymember{fetch_add}{atomic_ref<\placeholder{floating-point-type}>}% \indexlibrarymember{fetch_sub}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} @\placeholder{floating-point-type}@ fetch_@\placeholdernc{key}@(@\placeholder{floating-point-type}@ operand, memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Atomically replaces the value referenced by \tcode{*ptr} with the result of the computation applied to the value referenced by \tcode{*ptr} and the given operand. Memory is affected according to the value of \tcode{order}. These operations are atomic read-modify-write operations\iref{intro.races}. \pnum \returns Atomically, the value referenced by \tcode{*ptr} immediately before the effects. \pnum \remarks If the result is not a representable value for its type\iref{expr.pre}, the result is unspecified, but the operations otherwise have no undefined behavior. Atomic arithmetic operations on \tcode{\placeholder{floating-point-type}} should conform to the \tcode{std::numeric_limits<\placeholder{floating-point-type}>} traits associated with the floating-point type\iref{limits.syn}. The floating-point environment\iref{cfenv} for atomic arithmetic operations on \tcode{\placeholder{floating-point-type}} may be different than the calling thread's floating-point environment. \end{itemdescr} \indexlibrarymember{operator+=}{atomic_ref<\placeholder{floating-point-type}>}% \indexlibrarymember{operator-=}{atomic_ref<\placeholder{floating-point-type}>}% \begin{itemdecl} @\placeholder{floating-point-type}@ operator @\placeholder{op}@=(@\placeholder{floating-point-type}@ operand) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholdernc{op} operand;} \end{itemdescr} \rSec3[atomics.ref.pointer]{Partial specialization for pointers} \indexlibraryglobal{atomic_ref}% \begin{codeblock} namespace std { template struct atomic_ref { private: T** ptr; // \expos public: using value_type = T*; using difference_type = ptrdiff_t; static constexpr size_t required_alignment = @\impdefx{required alignment for \tcode{atomic_ref} type's operations}@; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic_ref} type's operations are always lock free}@; 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; }; } \end{codeblock} \pnum Descriptions are provided below only for members that differ from the primary template. \pnum The following operations perform arithmetic computations. The correspondence among key, operator, and computation is specified in \tref{atomic.types.pointer.comp}. \indexlibrarymember{fetch_add}{atomic_ref}% \indexlibrarymember{fetch_sub}{atomic_ref}% \begin{itemdecl} T* fetch_@\placeholdernc{key}@(difference_type operand, memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a complete object type. \pnum \effects Atomically replaces the value referenced by \tcode{*ptr} with the result of the computation applied to the value referenced by \tcode{*ptr} and the given operand. Memory is affected according to the value of \tcode{order}. These operations are atomic read-modify-write operations\iref{intro.races}. \pnum \returns Atomically, the value referenced by \tcode{*ptr} immediately before the effects. \pnum \remarks The result may be an undefined address, but the operations otherwise have no undefined behavior. \end{itemdescr} \indexlibrarymember{operator+=}{atomic_ref}% \indexlibrarymember{operator-=}{atomic_ref}% \begin{itemdecl} T* operator @\placeholder{op}@=(difference_type operand) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholdernc{op} operand;} \end{itemdescr} \rSec3[atomics.ref.memop]{Member operators common to integers and pointers to objects} \indexlibrarymember{operator++}{atomic_ref}% \indexlibrarymember{operator++}{atomic_ref<\placeholder{integral-type}>}% \begin{itemdecl} value_type operator++(int) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return fetch_add(1);} \end{itemdescr} \indexlibrarymember{operator--}{atomic_ref}% \indexlibrarymember{operator--}{atomic_ref<\placeholder{integral-type}>}% \begin{itemdecl} value_type operator--(int) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return fetch_sub(1);} \end{itemdescr} \indexlibrarymember{operator++}{atomic_ref}% \indexlibrarymember{operator++}{atomic_ref<\placeholder{integral-type}>}% \begin{itemdecl} value_type operator++() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return fetch_add(1) + 1;} \end{itemdescr} \indexlibrarymember{operator--}{atomic_ref}% \indexlibrarymember{operator--}{atomic_ref<\placeholder{integral-type}>}% \begin{itemdecl} value_type operator--() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return fetch_sub(1) - 1;} \end{itemdescr} \rSec2[atomics.types.generic]{Class template \tcode{atomic}} \rSec3[atomics.types.generic.general]{General} \indexlibraryglobal{atomic}% \indexlibrarymember{value_type}{atomic}% \begin{codeblock} namespace std { template struct atomic { using value_type = T; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; // \ref{atomics.types.operations}, operations on atomic types constexpr atomic() noexcept(is_nothrow_default_constructible_v); 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; }; } \end{codeblock} \indexlibraryglobal{atomic}% \pnum The template argument for \tcode{T} shall meet the \oldconcept{CopyConstructible} and \oldconcept{CopyAssignable} requirements. The program is ill-formed if any of \begin{itemize} \item \tcode{is_trivially_copyable_v}, \item \tcode{is_copy_constructible_v}, \item \tcode{is_move_constructible_v}, \item \tcode{is_copy_assignable_v}, or \item \tcode{is_move_assignable_v} \end{itemize} is \tcode{false}. \begin{note} Type arguments that are not also statically initializable can be difficult to use. \end{note} \pnum The specialization \tcode{atomic} is a standard-layout struct. \pnum \begin{note} The representation of an atomic specialization need not have the same size and alignment requirement as its corresponding argument type. \end{note} \rSec3[atomics.types.operations]{Operations on atomic types} \indexlibraryctor{atomic}% \indexlibraryctor{atomic}% \indexlibrary{\idxcode{atomic<\placeholder{integral-type}>}!constructor}% \indexlibrary{\idxcode{atomic<\placeholder{floating-point-type}>}!constructor}% \begin{itemdecl} constexpr atomic() noexcept(is_nothrow_default_constructible_v); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{is_default_constructible_v} is \tcode{true}. \pnum \effects Initializes the atomic object with the value of \tcode{T()}. Initialization is not an atomic operation\iref{intro.multithread}. \end{itemdescr} \indexlibraryctor{atomic}% \indexlibraryctor{atomic}% \indexlibrary{\idxcode{atomic<\placeholder{integral-type}>}!constructor}% \indexlibrary{\idxcode{atomic<\placeholder{floating-point-type}>}!constructor}% \begin{itemdecl} constexpr atomic(T desired) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes the object with the value \tcode{desired}. Initialization is not an atomic operation\iref{intro.multithread}. \begin{note} It is possible to have an access to an atomic object \tcode{A} race with its construction, for example by communicating the address of the just-constructed object \tcode{A} to another thread via \tcode{memory_order::relaxed} operations on a suitable atomic pointer variable, and then immediately accessing \tcode{A} in the receiving thread. This results in undefined behavior. \end{note} \end{itemdescr} \indexlibrarymember{is_always_lock_free}{atomic}% \indexlibrarymember{is_always_lock_free}{atomic}% \indexlibrarymember{is_always_lock_free}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{is_always_lock_free}{atomic<\placeholder{floating-point-type}>}% \indexlibrarymember{is_always_lock_free}{atomic>}% \indexlibrarymember{is_always_lock_free}{atomic>}% \begin{itemdecl} static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; \end{itemdecl} \begin{itemdescr} \pnum The \keyword{static} data member \tcode{is_always_lock_free} is \tcode{true} if the atomic type's operations are always lock-free, and \tcode{false} otherwise. \begin{note} The value of \tcode{is_always_lock_free} is consistent with the value of the corresponding \tcode{ATOMIC_..._LOCK_FREE} macro, if defined. \end{note} \end{itemdescr} \indexlibraryglobal{atomic_is_lock_free}% \indexlibrarymember{is_lock_free}{atomic}% \indexlibrarymember{is_lock_free}{atomic}% \indexlibrarymember{is_lock_free}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{is_lock_free}{atomic<\placeholder{floating-point-type}>}% \indexlibrarymember{is_lock_free}{atomic>}% \indexlibrarymember{is_lock_free}{atomic>}% \begin{itemdecl} bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if the object's operations are lock-free, \tcode{false} otherwise. \begin{note} The return value of the \tcode{is_lock_free} member function is consistent with the value of \tcode{is_always_lock_free} for the same type. \end{note} \end{itemdescr} \indexlibraryglobal{atomic_store}% \indexlibraryglobal{atomic_store_explicit}% \indexlibrarymember{store}{atomic}% \indexlibrarymember{store}{atomic}% \indexlibrarymember{store}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{store}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::release}, or \tcode{memory_order::seq_cst}. \pnum \effects Atomically replaces the value pointed to by \keyword{this} with the value of \tcode{desired}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} \indexlibrarymember{operator=}{atomic}% \indexlibrarymember{operator=}{atomic}% \indexlibrarymember{operator=}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{operator=}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} T operator=(T desired) volatile noexcept; T operator=(T desired) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to \tcode{store(desired)}. \pnum \returns \tcode{desired}. \end{itemdescr} \indexlibraryglobal{atomic_load}% \indexlibraryglobal{atomic_load_explicit}% \indexlibrarymember{load}{atomic}% \indexlibrarymember{load}{atomic}% \indexlibrarymember{load}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{load}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} T load(memory_order order = memory_order::seq_cst) const volatile noexcept; T load(memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Memory is affected according to the value of \tcode{order}. \pnum \returns Atomically returns the value pointed to by \keyword{this}. \end{itemdescr} \indexlibrarymember{operator \placeholder{type}}{atomic}% \indexlibrarymember{operator T*}{atomic}% \indexlibrarymember{operator \placeholder{integral-type}}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{operator \placeholder{floating-point-type}}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} operator T() const volatile noexcept; operator T() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to: \tcode{return load();} \end{itemdescr} \indexlibraryglobal{atomic_exchange}% \indexlibraryglobal{atomic_exchange_explicit}% \indexlibrarymember{exchange}{atomic}% \indexlibrarymember{exchange}{atomic}% \indexlibrarymember{exchange}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{exchange}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Atomically replaces the value pointed to by \keyword{this} with \tcode{desired}. Memory is affected according to the value of \tcode{order}. These operations are atomic read-modify-write operations\iref{intro.multithread}. \pnum \returns Atomically returns the value pointed to by \keyword{this} immediately before the effects. \end{itemdescr} \indexlibraryglobal{atomic_compare_exchange_weak}% \indexlibraryglobal{atomic_compare_exchange_strong}% \indexlibraryglobal{atomic_compare_exchange_weak_explicit}% \indexlibraryglobal{atomic_compare_exchange_strong_explicit}% \indexlibrarymember{compare_exchange_weak}{atomic}% \indexlibrarymember{compare_exchange_weak}{atomic}% \indexlibrarymember{compare_exchange_weak}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{compare_exchange_weak}{atomic<\placeholder{floating-point-type}>}% \indexlibrarymember{compare_exchange_strong}{atomic}% \indexlibrarymember{compare_exchange_strong}{atomic}% \indexlibrarymember{compare_exchange_strong}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{compare_exchange_strong}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \expects \tcode{failure} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac\-quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Retrieves the value in \tcode{expected}. It then atomically compares the value representation of the value pointed to by \keyword{this} for equality with that previously retrieved from \tcode{expected}, and if true, replaces the value pointed to by \keyword{this} with that in \tcode{desired}. If and only if the comparison is \tcode{true}, memory is affected according to the value of \tcode{success}, and if the comparison is false, memory is affected according to the value of \tcode{failure}. When only one \tcode{memory_order} argument is supplied, the value of \tcode{success} is \tcode{order}, and the value of \tcode{failure} is \tcode{order} except that a value of \tcode{memory_order::acq_rel} shall be replaced by the value \tcode{memory_order::acquire} and a value of \tcode{memory_order::release} shall be replaced by the value \tcode{memory_order::relaxed}. If and only if the comparison is false then, after the atomic operation, the value in \tcode{expected} is replaced by the value pointed to by \keyword{this} during the atomic comparison. If the operation returns \tcode{true}, these operations are atomic read-modify-write operations\iref{intro.multithread} on the memory pointed to by \keyword{this}. Otherwise, these operations are atomic load operations on that memory. \pnum \returns The result of the comparison. \pnum \begin{note} For example, the effect of \tcode{compare_exchange_strong} on objects without padding bits\iref{term.padding.bits} is \begin{codeblock} if (memcmp(this, &expected, sizeof(*this)) == 0) memcpy(this, &desired, sizeof(*this)); else memcpy(&expected, this, sizeof(*this)); \end{codeblock} \end{note} \begin{example} The expected use of the compare-and-exchange operations is as follows. The compare-and-exchange operations will update \tcode{expected} when another iteration of the loop is needed. \begin{codeblock} expected = current.load(); do { desired = function(expected); } while (!current.compare_exchange_weak(expected, desired)); \end{codeblock} \end{example} \begin{example} Because the expected value is updated only on failure, code releasing the memory containing the \tcode{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: \begin{codeblock} 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{codeblock} \end{example} \pnum Implementations should ensure that weak compare-and-exchange operations do not consistently return \tcode{false} unless either the atomic object has value different from \tcode{expected} or there are concurrent modifications to the atomic object. \pnum \remarks A weak compare-and-exchange operation may fail spuriously. That is, even when the contents of memory referred to by \tcode{expected} and \keyword{this} are equal, it may return \tcode{false} and store back to \tcode{expected} the same memory contents that were originally there. \begin{note} 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} \pnum \begin{note} Under cases where the \tcode{memcpy} and \tcode{memcmp} semantics of the compare-and-exchange operations apply, the comparisons can fail for values that compare equal with \tcode{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 \tcode{-0.0} and \tcode{+0.0} will not compare equal with \tcode{memcmp} but will compare equal with \tcode{operator==}, and NaNs with the same payload will compare equal with \tcode{memcmp} but will not compare equal with \tcode{operator==}. \end{note} \begin{note} 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: \begin{codeblock} struct padded { char clank = 0x42; // Padding here. unsigned biff = 0xC0DEFEFE; }; atomic pad = {}; bool zap() { padded expected, desired{0, 0}; return pad.compare_exchange_strong(expected, desired); } \end{codeblock} \end{note} \begin{note} 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: \begin{codeblock} union pony { double celestia = 0.; short luna; // padded }; atomic princesses = {}; bool party(pony desired) { pony expected; return princesses.compare_exchange_strong(expected, desired); } \end{codeblock} \end{note} \end{itemdescr} \indexlibrarymember{wait}{atomic}% \indexlibrarymember{wait}{atomic}% \indexlibrarymember{wait}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{wait}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Repeatedly performs the following steps, in order: \begin{itemize} \item Evaluates \tcode{load(order)} and compares its value representation for equality against that of \tcode{old}. \item If they compare unequal, returns. \item Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously. \end{itemize} \pnum \remarks This function is an atomic waiting operation\iref{atomics.wait}. \end{itemdescr} \indexlibrarymember{notify_one}{atomic}% \indexlibrarymember{notify_one}{atomic}% \indexlibrarymember{notify_one}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{notify_one}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} void notify_one() volatile noexcept; void notify_one() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of at least one atomic waiting operation that is eligible to be unblocked\iref{atomics.wait} by this call, if any such atomic waiting operations exist. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} \indexlibrarymember{notify_all}{atomic}% \indexlibrarymember{notify_all}{atomic}% \indexlibrarymember{notify_all}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{notify_all}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} void notify_all() volatile noexcept; void notify_all() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of all atomic waiting operations that are eligible to be unblocked\iref{atomics.wait} by this call. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} \rSec3[atomics.types.int]{Specializations for integers} \indexlibrary{\idxcode{atomic<\placeholder{integral-type}>}}% \pnum There are specializations of the \tcode{atomic} class template for the integral types \tcode{char}, \tcode{signed char}, \tcode{unsigned char}, \tcode{short}, \tcode{unsigned short}, \tcode{int}, \tcode{unsigned int}, \tcode{long}, \tcode{unsigned long}, \tcode{long long}, \tcode{unsigned long long}, \keyword{char8_t}, \keyword{char16_t}, \keyword{char32_t}, \keyword{wchar_t}, and any other types needed by the typedefs in the header \libheaderref{cstdint}. For each such type \tcode{\placeholder{integral-type}}, the specialization \tcode{atomic<\placeholder{integral-type}>} provides additional atomic operations appropriate to integral types. \begin{note} The specialization \tcode{atomic} uses the primary template\iref{atomics.types.generic}. \end{note} \begin{codeblock} namespace std { template<> struct atomic<@\placeholder{integral-type}@> { using value_type = @\placeholder{integral-type}@; using difference_type = value_type; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; constexpr atomic() noexcept; constexpr atomic(@\placeholdernc{integral-type}@) noexcept; atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; void store(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; void store(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ operator=(@\placeholdernc{integral-type}@) volatile noexcept; @\placeholdernc{integral-type}@ operator=(@\placeholdernc{integral-type}@) noexcept; @\placeholdernc{integral-type}@ load(memory_order = memory_order::seq_cst) const volatile noexcept; @\placeholdernc{integral-type}@ load(memory_order = memory_order::seq_cst) const noexcept; operator @\placeholdernc{integral-type}@() const volatile noexcept; operator @\placeholdernc{integral-type}@() const noexcept; @\placeholdernc{integral-type}@ exchange(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{integral-type}@ exchange(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order, memory_order) volatile noexcept; bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order, memory_order) noexcept; bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order, memory_order) volatile noexcept; bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order, memory_order) noexcept; bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; bool compare_exchange_weak(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; bool compare_exchange_strong(@\placeholder{integral-type}@&, @\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_add(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{integral-type}@ fetch_add(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_sub(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{integral-type}@ fetch_sub(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_and(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{integral-type}@ fetch_and(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_or(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{integral-type}@ fetch_or(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ fetch_xor(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{integral-type}@ fetch_xor(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{integral-type}@ operator++(int) volatile noexcept; @\placeholdernc{integral-type}@ operator++(int) noexcept; @\placeholdernc{integral-type}@ operator--(int) volatile noexcept; @\placeholdernc{integral-type}@ operator--(int) noexcept; @\placeholdernc{integral-type}@ operator++() volatile noexcept; @\placeholdernc{integral-type}@ operator++() noexcept; @\placeholdernc{integral-type}@ operator--() volatile noexcept; @\placeholdernc{integral-type}@ operator--() noexcept; @\placeholdernc{integral-type}@ operator+=(@\placeholdernc{integral-type}@) volatile noexcept; @\placeholdernc{integral-type}@ operator+=(@\placeholdernc{integral-type}@) noexcept; @\placeholdernc{integral-type}@ operator-=(@\placeholdernc{integral-type}@) volatile noexcept; @\placeholdernc{integral-type}@ operator-=(@\placeholdernc{integral-type}@) noexcept; @\placeholdernc{integral-type}@ operator&=(@\placeholdernc{integral-type}@) volatile noexcept; @\placeholdernc{integral-type}@ operator&=(@\placeholdernc{integral-type}@) noexcept; @\placeholdernc{integral-type}@ operator|=(@\placeholdernc{integral-type}@) volatile noexcept; @\placeholdernc{integral-type}@ operator|=(@\placeholdernc{integral-type}@) noexcept; @\placeholdernc{integral-type}@ operator^=(@\placeholdernc{integral-type}@) volatile noexcept; @\placeholdernc{integral-type}@ operator^=(@\placeholdernc{integral-type}@) noexcept; void wait(@\placeholdernc{integral-type}@, memory_order = memory_order::seq_cst) const volatile noexcept; void wait(@\placeholdernc{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; }; } \end{codeblock} \pnum The atomic integral specializations are standard-layout structs. They each have a trivial destructor. \pnum Descriptions are provided below only for members that differ from the primary template. \pnum The following operations perform arithmetic computations. The correspondence among key, operator, and computation is specified in \tref{atomic.types.int.comp}. \begin{floattable} {Atomic arithmetic computations}{atomic.types.int.comp}{lll|lll} \hline \hdstyle{\tcode{\placeholder{key}}} & \hdstyle{Op} & \hdstyle{Computation} & \hdstyle{\tcode{\placeholder{key}}} & \hdstyle{Op} & \hdstyle{Computation} \\ \hline \tcode{add} & \tcode{+} & addition & \tcode{sub} & \tcode{-} & subtraction \\ \tcode{or} & \tcode{|} & bitwise inclusive or & \tcode{xor} & \tcode{\caret} & bitwise exclusive or \\ \tcode{and} & \tcode{\&} & bitwise and &&&\\ \end{floattable} \indexlibraryglobal{atomic_fetch_add}% \indexlibraryglobal{atomic_fetch_and}% \indexlibraryglobal{atomic_fetch_or}% \indexlibraryglobal{atomic_fetch_sub}% \indexlibraryglobal{atomic_fetch_xor}% \indexlibraryglobal{atomic_fetch_add_explicit}% \indexlibraryglobal{atomic_fetch_and_explicit}% \indexlibraryglobal{atomic_fetch_or_explicit}% \indexlibraryglobal{atomic_fetch_sub_explicit}% \indexlibraryglobal{atomic_fetch_xor_explicit}% \indexlibrarymember{fetch_add}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{fetch_and}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{fetch_or}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{fetch_sub}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{fetch_xor}{atomic<\placeholder{integral-type}>}% \begin{itemdecl} T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Atomically replaces the value pointed to by \keyword{this} with the result of the computation applied to the value pointed to by \keyword{this} and the given \tcode{operand}. Memory is affected according to the value of \tcode{order}. These operations are atomic read-modify-write operations\iref{intro.multithread}. \pnum \returns Atomically, the value pointed to by \keyword{this} immediately before the effects. \pnum \indextext{signed integer representation!two's complement}% \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. \begin{note} There are no undefined results arising from the computation. \end{note} \end{itemdescr} \indexlibrarymember{operator+=}{atomic}% \indexlibrarymember{operator-=}{atomic}% \indexlibrarymember{operator+=}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{operator-=}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{operator\&=}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{operator"|=}{atomic<\placeholder{integral-type}>}% \indexlibrarymember{operator\caret=}{atomic<\placeholder{integral-type}>}% \begin{itemdecl} T operator @\placeholder{op}@=(T operand) volatile noexcept; T operator @\placeholder{op}@=(T operand) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} \end{itemdescr} \rSec3[atomics.types.float]{Specializations for floating-point types} \indexlibrary{\idxcode{atomic<\placeholder{floating-point-type}>}}% \pnum There are specializations of the \tcode{atomic} class template for all cv-unqualified floating-point types. For each such type \tcode{\placeholdernc{floating-point-type}}, the specialization \tcode{atomic<\placeholder{floating-point-type}>} provides additional atomic operations appropriate to floating-point types. \begin{codeblock} namespace std { template<> struct atomic<@\placeholder{floating-point-type}@> { using value_type = @\placeholdernc{floating-point-type}@; using difference_type = value_type; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; constexpr atomic() noexcept; constexpr atomic(@\placeholder{floating-point-type}@) noexcept; atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; void store(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) volatile noexcept; void store(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{floating-point-type}@ operator=(@\placeholder{floating-point-type}@) volatile noexcept; @\placeholdernc{floating-point-type}@ operator=(@\placeholder{floating-point-type}@) noexcept; @\placeholdernc{floating-point-type}@ load(memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{floating-point-type}@ load(memory_order = memory_order::seq_cst) noexcept; operator @\placeholdernc{floating-point-type}@() volatile noexcept; operator @\placeholdernc{floating-point-type}@() noexcept; @\placeholdernc{floating-point-type}@ exchange(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{floating-point-type}@ exchange(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order, memory_order) volatile noexcept; bool compare_exchange_weak(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order, memory_order) noexcept; bool compare_exchange_strong(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order, memory_order) volatile noexcept; bool compare_exchange_strong(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order, memory_order) noexcept; bool compare_exchange_weak(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) volatile noexcept; bool compare_exchange_weak(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) volatile noexcept; bool compare_exchange_strong(@\placeholder{floating-point-type}@&, @\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{floating-point-type}@ fetch_add(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{floating-point-type}@ fetch_add(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{floating-point-type}@ fetch_sub(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) volatile noexcept; @\placeholdernc{floating-point-type}@ fetch_sub(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) noexcept; @\placeholdernc{floating-point-type}@ operator+=(@\placeholder{floating-point-type}@) volatile noexcept; @\placeholdernc{floating-point-type}@ operator+=(@\placeholder{floating-point-type}@) noexcept; @\placeholdernc{floating-point-type}@ operator-=(@\placeholder{floating-point-type}@) volatile noexcept; @\placeholdernc{floating-point-type}@ operator-=(@\placeholder{floating-point-type}@) noexcept; void wait(@\placeholdernc{floating-point-type}@, memory_order = memory_order::seq_cst) const volatile noexcept; void wait(@\placeholdernc{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; }; } \end{codeblock} \pnum The atomic floating-point specializations are standard-layout structs. They each have a trivial destructor. \pnum Descriptions are provided below only for members that differ from the primary template. \pnum The following operations perform arithmetic addition and subtraction computations. The correspondence among key, operator, and computation is specified in \tref{atomic.types.int.comp}. \indexlibraryglobal{atomic_fetch_add}% \indexlibraryglobal{atomic_fetch_sub}% \indexlibraryglobal{atomic_fetch_add_explicit}% \indexlibraryglobal{atomic_fetch_sub_explicit}% \indexlibrarymember{fetch_add}{atomic<\placeholder{floating-point-type}>}% \indexlibrarymember{fetch_sub}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) volatile noexcept; T fetch_@\placeholdernc{key}@(T operand, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Atomically replaces the value pointed to by \keyword{this} with the result of the computation applied to the value pointed to by \keyword{this} and the given \tcode{operand}. Memory is affected according to the value of \tcode{order}. These operations are atomic read-modify-write operations\iref{intro.multithread}. \pnum \returns Atomically, the value pointed to by \keyword{this} immediately before the effects. \pnum \remarks If the result is not a representable value for its type\iref{expr.pre} the result is unspecified, but the operations otherwise have no undefined behavior. Atomic arithmetic operations on \tcode{\placeholder{floating-point-type}} should conform to the \tcode{std::numeric_limits<\placeholder{floating-point-type}>} traits associated with the floating-point type\iref{limits.syn}. The floating-point environment\iref{cfenv} for atomic arithmetic operations on \tcode{\placeholder{floating-point-type}} may be different than the calling thread's floating-point environment. \end{itemdescr} \indexlibrarymember{operator+=}{atomic}% \indexlibrarymember{operator-=}{atomic}% \indexlibrarymember{operator+=}{atomic<\placeholder{floating-point-type}>}% \indexlibrarymember{operator-=}{atomic<\placeholder{floating-point-type}>}% \begin{itemdecl} T operator @\placeholder{op}@=(T operand) volatile noexcept; T operator @\placeholder{op}@=(T operand) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} \pnum \remarks If the result is not a representable value for its type\iref{expr.pre} the result is unspecified, but the operations otherwise have no undefined behavior. Atomic arithmetic operations on \tcode{\placeholder{floating-point-type}} should conform to the \tcode{std::numeric_limits<\placeholder{floating-point-type}>} traits associated with the floating-point type\iref{limits.syn}. The floating-point environment\iref{cfenv} for atomic arithmetic operations on \tcode{\placeholder{floating-point-type}} may be different than the calling thread's floating-point environment. \end{itemdescr} \rSec3[atomics.types.pointer]{Partial specialization for pointers} \indexlibraryglobal{atomic}% \begin{codeblock} namespace std { template struct atomic { using value_type = T*; using difference_type = ptrdiff_t; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; 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; }; } \end{codeblock} \indexlibraryglobal{atomic}% \pnum There is a partial specialization of the \tcode{atomic} class template for pointers. Specializations of this partial specialization are standard-layout structs. They each have a trivial destructor. \pnum Descriptions are provided below only for members that differ from the primary template. \pnum The following operations perform pointer arithmetic. The correspondence among key, operator, and computation is specified in \tref{atomic.types.pointer.comp}. \begin{floattable} {Atomic pointer computations}{atomic.types.pointer.comp}{lll|lll} \hline \hdstyle{\tcode{\placeholder{key}}} & \hdstyle{Op} & \hdstyle{Computation} & \hdstyle{\tcode{\placeholder{key}}} & \hdstyle{Op} & \hdstyle{Computation} \\ \hline \tcode{add} & \tcode{+} & addition & \tcode{sub} & \tcode{-} & subtraction \\ \end{floattable} \indexlibraryglobal{atomic_fetch_add}% \indexlibraryglobal{atomic_fetch_sub}% \indexlibraryglobal{atomic_fetch_add_explicit}% \indexlibraryglobal{atomic_fetch_sub_explicit}% \indexlibrarymember{fetch_add}{atomic}% \indexlibrarymember{fetch_sub}{atomic}% \begin{itemdecl} T* fetch_@\placeholdernc{key}@(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept; T* fetch_@\placeholdernc{key}@(ptrdiff_t operand, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \mandates \tcode{T} is a complete object type. \begin{note} Pointer arithmetic on \tcode{void*} or function pointers is ill-formed. \end{note} \pnum \effects Atomically replaces the value pointed to by \keyword{this} with the result of the computation applied to the value pointed to by \keyword{this} and the given \tcode{operand}. Memory is affected according to the value of \tcode{order}. These operations are atomic read-modify-write operations\iref{intro.multithread}. \pnum \returns Atomically, the value pointed to by \keyword{this} immediately before the effects. \pnum \remarks The result may be an undefined address, but the operations otherwise have no undefined behavior. \end{itemdescr} \indexlibrarymember{operator+=}{atomic}% \indexlibrarymember{operator-=}{atomic}% \begin{itemdecl} T* operator @\placeholder{op}@=(ptrdiff_t operand) volatile noexcept; T* operator @\placeholder{op}@=(ptrdiff_t operand) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to: \tcode{return fetch_\placeholder{key}(operand) \placeholder{op} operand;} \end{itemdescr} \rSec3[atomics.types.memop]{Member operators common to integers and pointers to objects} \indexlibrarymember{operator++}{atomic}% \indexlibrarymember{operator++}{atomic<\placeholder{integral-type}>}% \begin{itemdecl} value_type operator++(int) volatile noexcept; value_type operator++(int) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to: \tcode{return fetch_add(1);} \end{itemdescr} \indexlibrarymember{operator--}{atomic}% \indexlibrarymember{operator--}{atomic<\placeholder{integral-type}>}% \begin{itemdecl} value_type operator--(int) volatile noexcept; value_type operator--(int) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to: \tcode{return fetch_sub(1);} \end{itemdescr} \indexlibrarymember{operator++}{atomic}% \indexlibrarymember{operator++}{atomic<\placeholder{integral-type}>}% \begin{itemdecl} value_type operator++() volatile noexcept; value_type operator++() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to: \tcode{return fetch_add(1) + 1;} \end{itemdescr} \indexlibrarymember{operator--}{atomic}% \indexlibrarymember{operator--}{atomic<\placeholder{integral-type}>}% \begin{itemdecl} value_type operator--() volatile noexcept; value_type operator--() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the \tcode{volatile} overload of this function, \tcode{is_always_lock_free} is \tcode{true}. \pnum \effects Equivalent to: \tcode{return fetch_sub(1) - 1;} \end{itemdescr} \rSec3[util.smartptr.atomic]{Partial specializations for smart pointers}% \indextext{atomic!smart pointers|(}% \rSec4[util.smartptr.atomic.general]{General} \pnum The library provides partial specializations of the \tcode{atomic} template for shared-ownership smart pointers\iref{util.sharedptr}. \begin{note} The partial specializations are declared in header \libheaderref{memory}. \end{note} The behavior of all operations is as specified in \ref{atomics.types.generic}, unless specified otherwise. The template parameter \tcode{T} of these partial specializations may be an incomplete type. \pnum All changes to an atomic smart pointer in \ref{util.smartptr.atomic}, and all associated \tcode{use_count} increments, are guaranteed to be performed atomically. Associated \tcode{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. \begin{note} If the atomic operation uses locks, locks acquired by the implementation will be held when any \tcode{use_count} adjustments are performed, and will not be held when any destruction or deallocation resulting from this is performed. \end{note} \pnum \begin{example} \begin{codeblock} template class atomic_list { struct node { T t; shared_ptr next; }; atomic> head; public: shared_ptr 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(); p->t = t; p->next = head; while (!head.compare_exchange_weak(p->next, p)) {} } }; \end{codeblock} \end{example} \rSec4[util.smartptr.atomic.shared]{Partial specialization for \tcode{shared_ptr}} \indexlibraryglobal{atomic>}% \begin{codeblock} namespace std { template struct atomic> { using value_type = shared_ptr; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; bool is_lock_free() const noexcept; constexpr atomic() noexcept; constexpr atomic(nullptr_t) noexcept : atomic() { } atomic(shared_ptr desired) noexcept; atomic(const atomic&) = delete; void operator=(const atomic&) = delete; shared_ptr load(memory_order order = memory_order::seq_cst) const noexcept; operator shared_ptr() const noexcept; void store(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; void operator=(shared_ptr desired) noexcept; void operator=(nullptr_t) noexcept; shared_ptr exchange(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; void notify_one() noexcept; void notify_all() noexcept; private: shared_ptr p; // \expos }; } \end{codeblock} \indexlibraryctor{atomic>}% \begin{itemdecl} constexpr atomic() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{p\{\}}. \end{itemdescr} \indexlibraryctor{atomic>}% \begin{itemdecl} atomic(shared_ptr desired) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes the object with the value \tcode{desired}. Initialization is not an atomic operation\iref{intro.multithread}. \begin{note} It is possible to have an access to an atomic object \tcode{A} race with its construction, for example, by communicating the address of the just-constructed object \tcode{A} to another thread via \tcode{memory_order::relaxed} operations on a suitable atomic pointer variable, and then immediately accessing \tcode{A} in the receiving thread. This results in undefined behavior. \end{note} \end{itemdescr} \indexlibrarymember{store}{atomic>}% \begin{itemdecl} void store(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::release}, or \tcode{memory_order::seq_cst}. \pnum \effects Atomically replaces the value pointed to by \keyword{this} with the value of \tcode{desired} as if by \tcode{p.swap(desired)}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} \indexlibrarymember{operator=}{atomic>}% \begin{itemdecl} void operator=(shared_ptr desired) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{store(desired)}. \end{itemdescr} \indexlibrarymember{operator=}{atomic>}% \begin{itemdecl} void operator=(nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{store(nullptr)}. \end{itemdescr} \indexlibrarymember{load}{atomic>}% \begin{itemdecl} shared_ptr load(memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Memory is affected according to the value of \tcode{order}. \pnum \returns Atomically returns \tcode{p}. \end{itemdescr} \indexlibrarymember{operator shared_ptr}{atomic>}% \begin{itemdecl} operator shared_ptr() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return load();} \end{itemdescr} \indexlibrarymember{exchange}{atomic>}% \begin{itemdecl} shared_ptr exchange(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Atomically replaces \tcode{p} with \tcode{desired} as if by \tcode{p.swap(desired)}. Memory is affected according to the value of \tcode{order}. This is an atomic read-modify-write operation\iref{intro.races}. \pnum \returns Atomically returns the value of \tcode{p} immediately before the effects. \end{itemdescr} \indexlibrarymember{compare_exchange_weak}{atomic>}% \indexlibrarymember{compare_exchange_strong}{atomic>}% \begin{itemdecl} bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, memory_order success, memory_order failure) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{failure} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac\-quire}, or \tcode{memory_order::seq_cst}. \pnum \effects If \tcode{p} is equivalent to \tcode{expected}, assigns \tcode{desired} to \tcode{p} and has synchronization semantics corresponding to the value of \tcode{success}, otherwise assigns \tcode{p} to \tcode{expected} and has synchronization semantics corresponding to the value of \tcode{failure}. \pnum \returns \tcode{true} if \tcode{p} was equivalent to \tcode{expected}, \tcode{false} otherwise. \pnum \remarks Two \tcode{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. See \ref{atomics.types.operations}. \pnum If the operation returns \tcode{true}, \tcode{expected} is not accessed after the atomic update and the operation is an atomic read-modify-write operation\iref{intro.multithread} on the memory pointed to by \keyword{this}. Otherwise, the operation is an atomic load operation on that memory, and \tcode{expected} is updated with the existing value read from the atomic object in the attempted atomic update. The \tcode{use_count} update corresponding to the write to \tcode{expected} is part of the atomic operation. The write to \tcode{expected} itself is not required to be part of the atomic operation. \end{itemdescr} \indexlibrarymember{compare_exchange_weak}{atomic>}% \begin{itemdecl} bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return compare_exchange_weak(expected, desired, order, fail_order); \end{codeblock} where \tcode{fail_order} is the same as \tcode{order} except that a value of \tcode{memory_order::acq_rel} shall be replaced by the value \tcode{memory_order::acquire} and a value of \tcode{memory_order::release} shall be replaced by the value \tcode{memory_order::relaxed}. \end{itemdescr} \indexlibrarymember{compare_exchange_strong}{atomic>}% \begin{itemdecl} bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return compare_exchange_strong(expected, desired, order, fail_order); \end{codeblock} where \tcode{fail_order} is the same as \tcode{order} except that a value of \tcode{memory_order::acq_rel} shall be replaced by the value \tcode{memory_order::acquire} and a value of \tcode{memory_order::release} shall be replaced by the value \tcode{memory_order::relaxed}. \end{itemdescr} \indexlibrarymember{wait}{atomic>}% \begin{itemdecl} void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Repeatedly performs the following steps, in order: \begin{itemize} \item Evaluates \tcode{load(order)} and compares it to \tcode{old}. \item If the two are not equivalent, returns. \item Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously. \end{itemize} \pnum \remarks Two \tcode{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\iref{atomics.wait}. \end{itemdescr} \indexlibrarymember{notify_one}{atomic>}% \begin{itemdecl} void notify_one() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of at least one atomic waiting operation that is eligible to be unblocked\iref{atomics.wait} by this call, if any such atomic waiting operations exist. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} \indexlibrarymember{notify_all}{atomic>}% \begin{itemdecl} void notify_all() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of all atomic waiting operations that are eligible to be unblocked\iref{atomics.wait} by this call. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} \rSec4[util.smartptr.atomic.weak]{Partial specialization for \tcode{weak_ptr}} \indexlibraryglobal{atomic>}% \begin{codeblock} namespace std { template struct atomic> { using value_type = weak_ptr; static constexpr bool is_always_lock_free = @\impdefx{whether a given \tcode{atomic} type's operations are always lock free}@; bool is_lock_free() const noexcept; constexpr atomic() noexcept; atomic(weak_ptr desired) noexcept; atomic(const atomic&) = delete; void operator=(const atomic&) = delete; weak_ptr load(memory_order order = memory_order::seq_cst) const noexcept; operator weak_ptr() const noexcept; void store(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; void operator=(weak_ptr desired) noexcept; weak_ptr exchange(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; void notify_one() noexcept; void notify_all() noexcept; private: weak_ptr p; // \expos }; } \end{codeblock} \indexlibraryctor{atomic>}% \begin{itemdecl} constexpr atomic() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{p\{\}}. \end{itemdescr} \indexlibraryctor{atomic>}% \begin{itemdecl} atomic(weak_ptr desired) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes the object with the value \tcode{desired}. Initialization is not an atomic operation\iref{intro.multithread}. \begin{note} It is possible to have an access to an atomic object \tcode{A} race with its construction, for example, by communicating the address of the just-constructed object \tcode{A} to another thread via \tcode{memory_order::relaxed} operations on a suitable atomic pointer variable, and then immediately accessing \tcode{A} in the receiving thread. This results in undefined behavior. \end{note} \end{itemdescr} \indexlibrarymember{store}{atomic>}% \begin{itemdecl} void store(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::release}, or \tcode{memory_order::seq_cst}. \pnum \effects Atomically replaces the value pointed to by \keyword{this} with the value of \tcode{desired} as if by \tcode{p.swap(desired)}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} \indexlibrarymember{operator=}{atomic>}% \begin{itemdecl} void operator=(weak_ptr desired) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{store(desired)}. \end{itemdescr} \indexlibrarymember{load}{atomic>}% \begin{itemdecl} weak_ptr load(memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Memory is affected according to the value of \tcode{order}. \pnum \returns Atomically returns \tcode{p}. \end{itemdescr} \indexlibrarymember{operator weak_ptr}{atomic>}% \begin{itemdecl} operator weak_ptr() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return load();} \end{itemdescr} \indexlibrarymember{exchange}{atomic>}% \begin{itemdecl} weak_ptr exchange(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Atomically replaces \tcode{p} with \tcode{desired} as if by \tcode{p.swap(desired)}. Memory is affected according to the value of \tcode{order}. This is an atomic read-modify-write operation\iref{intro.races}. \pnum \returns Atomically returns the value of \tcode{p} immediately before the effects. \end{itemdescr} \indexlibrarymember{compare_exchange_weak}{atomic>}% \begin{itemdecl} bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, memory_order success, memory_order failure) noexcept; bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, memory_order success, memory_order failure) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{failure} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac\-quire}, or \tcode{memory_order::seq_cst}. \pnum \effects If \tcode{p} is equivalent to \tcode{expected}, assigns \tcode{desired} to \tcode{p} and has synchronization semantics corresponding to the value of \tcode{success}, otherwise assigns \tcode{p} to \tcode{expected} and has synchronization semantics corresponding to the value of \tcode{failure}. \pnum \returns \tcode{true} if \tcode{p} was equivalent to \tcode{expected}, \tcode{false} otherwise. \pnum \remarks Two \tcode{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. See \ref{atomics.types.operations}. \pnum If the operation returns \tcode{true}, \tcode{expected} is not accessed after the atomic update and the operation is an atomic read-modify-write operation\iref{intro.multithread} on the memory pointed to by \keyword{this}. Otherwise, the operation is an atomic load operation on that memory, and \tcode{expected} is updated with the existing value read from the atomic object in the attempted atomic update. The \tcode{use_count} update corresponding to the write to \tcode{expected} is part of the atomic operation. The write to \tcode{expected} itself is not required to be part of the atomic operation. \end{itemdescr} \indexlibrarymember{compare_exchange_weak}{atomic>}% \begin{itemdecl} bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return compare_exchange_weak(expected, desired, order, fail_order); \end{codeblock} where \tcode{fail_order} is the same as \tcode{order} except that a value of \tcode{memory_order::acq_rel} shall be replaced by the value \tcode{memory_order::acquire} and a value of \tcode{memory_order::release} shall be replaced by the value \tcode{memory_order::relaxed}. \end{itemdescr} \indexlibrarymember{compare_exchange_strong}{atomic>}% \begin{itemdecl} bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return compare_exchange_strong(expected, desired, order, fail_order); \end{codeblock} where \tcode{fail_order} is the same as \tcode{order} except that a value of \tcode{memory_order::acq_rel} shall be replaced by the value \tcode{memory_order::acquire} and a value of \tcode{memory_order::release} shall be replaced by the value \tcode{memory_order::relaxed}. \end{itemdescr} \indexlibrarymember{wait}{atomic>}% \begin{itemdecl} void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Repeatedly performs the following steps, in order: \begin{itemize} \item Evaluates \tcode{load(order)} and compares it to \tcode{old}. \item If the two are not equivalent, returns. \item Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously. \end{itemize} \pnum \remarks Two \tcode{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\iref{atomics.wait}. \end{itemdescr} \indexlibrarymember{notify_one}{atomic>}% \begin{itemdecl} void notify_one() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of at least one atomic waiting operation that is eligible to be unblocked\iref{atomics.wait} by this call, if any such atomic waiting operations exist. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} \indexlibrarymember{notify_all}{atomic>}% \begin{itemdecl} void notify_all() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of all atomic waiting operations that are eligible to be unblocked\iref{atomics.wait} by this call. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} \indextext{atomic!smart pointers|)} \rSec2[atomics.nonmembers]{Non-member functions} \pnum A non-member function template whose name matches the pattern \tcode{atomic_\placeholder{f}} or the pattern \tcode{atomic_\placeholder{f}_explicit} invokes the member function \tcode{\placeholder{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 \tcode{atomic::value_type*} is dereferenced when passed to the member function call. If no such member function exists, the program is ill-formed. \pnum \begin{note} The non-member functions enable programmers to write code that can be compiled as either C or \Cpp{}, for example in a shared header file. \end{note} \rSec2[atomics.flag]{Flag type and operations} \begin{codeblock} 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; }; } \end{codeblock} \pnum The \tcode{atomic_flag} type provides the classic test-and-set functionality. It has two states, set and clear. \pnum Operations on an object of type \tcode{atomic_flag} shall be lock-free. The operations should also be address-free. \pnum The \tcode{atomic_flag} type is a standard-layout struct. It has a trivial destructor. \indexlibraryctor{atomic_flag}% \begin{itemdecl} constexpr atomic_flag::atomic_flag() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{*this} to the clear state. \end{itemdescr} \indexlibraryglobal{atomic_flag_test}% \indexlibraryglobal{atomic_flag_test_explicit}% \indexlibrarymember{test}{atomic_flag}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum For \tcode{atomic_flag_test}, let \tcode{order} be \tcode{memory_order::seq_cst}. \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Memory is affected according to the value of \tcode{order}. \pnum \returns Atomically returns the value pointed to by \tcode{object} or \keyword{this}. \end{itemdescr} \indexlibraryglobal{atomic_flag_test_and_set}% \indexlibraryglobal{atomic_flag_test_and_set_explicit}% \indexlibrarymember{test_and_set}{atomic_flag}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \effects Atomically sets the value pointed to by \tcode{object} or by \keyword{this} to \tcode{true}. Memory is affected according to the value of \tcode{order}. These operations are atomic read-modify-write operations\iref{intro.multithread}. \pnum \returns Atomically, the value of the object immediately before the effects. \end{itemdescr} \indexlibraryglobal{atomic_flag_clear}% \indexlibraryglobal{atomic_flag_clear_explicit}% \indexlibrarymember{clear}{atomic_flag}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::release}, or \tcode{memory_order::seq_cst}. \pnum \effects Atomically sets the value pointed to by \tcode{object} or by \keyword{this} to \tcode{false}. Memory is affected according to the value of \tcode{order}. \end{itemdescr} \indexlibraryglobal{atomic_flag_wait}% \indexlibraryglobal{atomic_flag_wait_explicit}% \indexlibrarymember{wait}{atomic_flag}% \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum For \tcode{atomic_flag_wait}, let \tcode{order} be \tcode{memory_order::seq_cst}. Let \tcode{flag} be \tcode{object} for the non-member functions and \keyword{this} for the member functions. \pnum \expects \tcode{order} is \tcode{memory_order::relaxed}, \tcode{memory_order::consume}, \tcode{memory_order::ac-\linebreak quire}, or \tcode{memory_order::seq_cst}. \pnum \effects Repeatedly performs the following steps, in order: \begin{itemize} \item Evaluates \tcode{flag->test(order) != old}. \item If the result of that evaluation is \tcode{true}, returns. \item Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously. \end{itemize} \pnum \remarks This function is an atomic waiting operation\iref{atomics.wait}. \end{itemdescr} \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of at least one atomic waiting operation that is eligible to be unblocked\iref{atomics.wait} by this call, if any such atomic waiting operations exist. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} \begin{itemdecl} 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; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks the execution of all atomic waiting operations that are eligible to be unblocked\iref{atomics.wait} by this call. \pnum \remarks This function is an atomic notifying operation\iref{atomics.wait}. \end{itemdescr} \indexlibraryglobal{ATOMIC_FLAG_INIT}% \begin{itemdecl} #define ATOMIC_FLAG_INIT @\seebelow@ \end{itemdecl} \begin{itemdescr} \pnum \remarks The macro \tcode{ATOMIC_FLAG_INIT} is defined in such a way that it can be used to initialize an object of type \tcode{atomic_flag} to the clear state. The macro can be used in the form: \begin{codeblock} atomic_flag guard = ATOMIC_FLAG_INIT; \end{codeblock} It is unspecified whether the macro can be used in other initialization contexts. For a complete static-duration object, that initialization shall be static. \end{itemdescr} \rSec2[atomics.fences]{Fences} \pnum This subclause introduces synchronization primitives called \term{fences}. Fences can have acquire semantics, release semantics, or both. A fence with acquire semantics is called an \term{acquire fence}. A fence with release semantics is called a \term{release fence}. \pnum 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. \pnum 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. \pnum 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$. \indexlibraryglobal{atomic_thread_fence}% \begin{itemdecl} extern "C" void atomic_thread_fence(memory_order order) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Depending on the value of \tcode{order}, this operation: \begin{itemize} \item has no effects, if \tcode{order == memory_order::relaxed}; \item is an acquire fence, if \tcode{order == memory_order::acquire} or \tcode{order == memory_order::consume}; \item is a release fence, if \tcode{order == memory_order::release}; \item is both an acquire fence and a release fence, if \tcode{order == memory_order::acq_rel}; \item is a sequentially consistent acquire and release fence, if \tcode{order == memory_order::seq_cst}. \end{itemize} \end{itemdescr} \indexlibraryglobal{atomic_signal_fence}% \begin{itemdecl} extern "C" void atomic_signal_fence(memory_order order) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{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. \pnum \begin{note} \tcode{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 \tcode{atomic_thread_fence}, but the hardware fence instructions that \tcode{atomic_thread_fence} would have inserted are not emitted. \end{note} \end{itemdescr} \rSec2[stdatomic.h.syn]{C compatibility} The header \libheaderdef{stdatomic.h} provides the following definitions: \begin{codeblock} template using @\exposid{std-atomic}@ = std::atomic; // \expos #define _Atomic(T) @\exposid{std-atomic}@ #define ATOMIC_BOOL_LOCK_FREE @\seebelow@ #define ATOMIC_CHAR_LOCK_FREE @\seebelow@ #define ATOMIC_CHAR16_T_LOCK_FREE @\seebelow@ #define ATOMIC_CHAR32_T_LOCK_FREE @\seebelow@ #define ATOMIC_WCHAR_T_LOCK_FREE @\seebelow@ #define ATOMIC_SHORT_LOCK_FREE @\seebelow@ #define ATOMIC_INT_LOCK_FREE @\seebelow@ #define ATOMIC_LONG_LOCK_FREE @\seebelow@ #define ATOMIC_LLONG_LOCK_FREE @\seebelow@ #define ATOMIC_POINTER_LOCK_FREE @\seebelow@ using std::@\libglobal{memory_order}@; // \seebelow using std::@\libglobal{memory_order_relaxed}@; // \seebelow using std::@\libglobal{memory_order_consume}@; // \seebelow using std::@\libglobal{memory_order_acquire}@; // \seebelow using std::@\libglobal{memory_order_release}@; // \seebelow using std::@\libglobal{memory_order_acq_rel}@; // \seebelow using std::@\libglobal{memory_order_seq_cst}@; // \seebelow using std::@\libglobal{atomic_flag}@; // \seebelow using std::@\libglobal{atomic_bool}@; // \seebelow using std::@\libglobal{atomic_char}@; // \seebelow using std::@\libglobal{atomic_schar}@; // \seebelow using std::@\libglobal{atomic_uchar}@; // \seebelow using std::@\libglobal{atomic_short}@; // \seebelow using std::@\libglobal{atomic_ushort}@; // \seebelow using std::@\libglobal{atomic_int}@; // \seebelow using std::@\libglobal{atomic_uint}@; // \seebelow using std::@\libglobal{atomic_long}@; // \seebelow using std::@\libglobal{atomic_ulong}@; // \seebelow using std::@\libglobal{atomic_llong}@; // \seebelow using std::@\libglobal{atomic_ullong}@; // \seebelow using std::@\libglobal{atomic_char8_t}@; // \seebelow using std::@\libglobal{atomic_char16_t}@; // \seebelow using std::@\libglobal{atomic_char32_t}@; // \seebelow using std::@\libglobal{atomic_wchar_t}@; // \seebelow using std::@\libglobal{atomic_int8_t}@; // \seebelow using std::@\libglobal{atomic_uint8_t}@; // \seebelow using std::@\libglobal{atomic_int16_t}@; // \seebelow using std::@\libglobal{atomic_uint16_t}@; // \seebelow using std::@\libglobal{atomic_int32_t}@; // \seebelow using std::@\libglobal{atomic_uint32_t}@; // \seebelow using std::@\libglobal{atomic_int64_t}@; // \seebelow using std::@\libglobal{atomic_uint64_t}@; // \seebelow using std::@\libglobal{atomic_int_least8_t}@; // \seebelow using std::@\libglobal{atomic_uint_least8_t}@; // \seebelow using std::@\libglobal{atomic_int_least16_t}@; // \seebelow using std::@\libglobal{atomic_uint_least16_t}@; // \seebelow using std::@\libglobal{atomic_int_least32_t}@; // \seebelow using std::@\libglobal{atomic_uint_least32_t}@; // \seebelow using std::@\libglobal{atomic_int_least64_t}@; // \seebelow using std::@\libglobal{atomic_uint_least64_t}@; // \seebelow using std::@\libglobal{atomic_int_fast8_t}@; // \seebelow using std::@\libglobal{atomic_uint_fast8_t}@; // \seebelow using std::@\libglobal{atomic_int_fast16_t}@; // \seebelow using std::@\libglobal{atomic_uint_fast16_t}@; // \seebelow using std::@\libglobal{atomic_int_fast32_t}@; // \seebelow using std::@\libglobal{atomic_uint_fast32_t}@; // \seebelow using std::@\libglobal{atomic_int_fast64_t}@; // \seebelow using std::@\libglobal{atomic_uint_fast64_t}@; // \seebelow using std::@\libglobal{atomic_intptr_t}@; // \seebelow using std::@\libglobal{atomic_uintptr_t}@; // \seebelow using std::@\libglobal{atomic_size_t}@; // \seebelow using std::@\libglobal{atomic_ptrdiff_t}@; // \seebelow using std::@\libglobal{atomic_intmax_t}@; // \seebelow using std::@\libglobal{atomic_uintmax_t}@; // \seebelow using std::@\libglobal{atomic_is_lock_free}@; // \seebelow using std::@\libglobal{atomic_load}@; // \seebelow using std::@\libglobal{atomic_load_explicit}@; // \seebelow using std::@\libglobal{atomic_store}@; // \seebelow using std::@\libglobal{atomic_store_explicit}@; // \seebelow using std::@\libglobal{atomic_exchange}@; // \seebelow using std::@\libglobal{atomic_exchange_explicit}@; // \seebelow using std::@\libglobal{atomic_compare_exchange_strong}@; // \seebelow using std::@\libglobal{atomic_compare_exchange_strong_explicit}@; // \seebelow using std::@\libglobal{atomic_compare_exchange_weak}@; // \seebelow using std::@\libglobal{atomic_compare_exchange_weak_explicit}@; // \seebelow using std::@\libglobal{atomic_fetch_add}@; // \seebelow using std::@\libglobal{atomic_fetch_add_explicit}@; // \seebelow using std::@\libglobal{atomic_fetch_sub}@; // \seebelow using std::@\libglobal{atomic_fetch_sub_explicit}@; // \seebelow using std::@\libglobal{atomic_fetch_and}@; // \seebelow using std::@\libglobal{atomic_fetch_and_explicit}@; // \seebelow using std::@\libglobal{atomic_fetch_or}@; // \seebelow using std::@\libglobal{atomic_fetch_or_explicit}@; // \seebelow using std::@\libglobal{atomic_fetch_xor}@; // \seebelow using std::@\libglobal{atomic_fetch_xor_explicit}@; // \seebelow using std::@\libglobal{atomic_flag_test_and_set}@; // \seebelow using std::@\libglobal{atomic_flag_test_and_set_explicit}@; // \seebelow using std::@\libglobal{atomic_flag_clear}@; // \seebelow using std::@\libglobal{atomic_flag_clear_explicit}@; // \seebelow #define ATOMIC_FLAG_INIT @\seebelow@ using std::@\libglobal{atomic_thread_fence}@; // \seebelow using std::@\libglobal{atomic_signal_fence}@; // \seebelow \end{codeblock} \pnum Each \grammarterm{using-declaration} for some name $A$ in the synopsis above makes available the same entity as \tcode{std::$A$} declared in \libheaderrefx{atomic}{atomics.syn}. Each macro listed above other than \tcode{_Atomic(T)} is defined as in \libheader{atomic}. It is unspecified whether \libheader{stdatomic.h} makes available any declarations in namespace \tcode{std}. \pnum Each of the \grammarterm{using-declaration}s for \tcode{int$N$_t}, \tcode{uint$N$_t}, \tcode{intptr_t}, and \tcode{uintptr_t} listed above is defined if and only if the implementation defines the corresponding \grammarterm{typedef-name} in \ref{atomics.syn}. \pnum Neither the \tcode{_Atomic} macro, nor any of the non-macro global namespace declarations, are provided by any \Cpp{} standard library header other than \libheader{stdatomic.h}. \pnum \recommended Implementations should ensure that C and \Cpp{} representations of atomic objects are compatible, so that the same object can be accessed as both an \tcode{_Atomic(T)} from C code and an \tcode{atomic} from \Cpp{} code. The representations should be the same, and the mechanisms used to ensure atomicity and memory ordering should be compatible. \rSec1[thread.mutex]{Mutual exclusion} \rSec2[thread.mutex.general]{General} \pnum Subclause \ref{thread.mutex} provides mechanisms for mutual exclusion: mutexes, locks, and call once. These mechanisms ease the production of race-free programs\iref{intro.multithread}. \rSec2[mutex.syn]{Header \tcode{} synopsis} \indexheader{mutex}% \begin{codeblock} namespace std { // \ref{thread.mutex.class}, class \tcode{mutex} class mutex; // \ref{thread.mutex.recursive}, class \tcode{recursive_mutex} class recursive_mutex; // \ref{thread.timedmutex.class} class \tcode{timed_mutex} class timed_mutex; // \ref{thread.timedmutex.recursive}, class \tcode{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 { }; // \ref{thread.lock}, locks template class lock_guard; template class scoped_lock; template class unique_lock; template void swap(unique_lock& x, unique_lock& y) noexcept; // \ref{thread.lock.algorithm}, generic locking algorithms template int try_lock(L1&, L2&, L3&...); template void lock(L1&, L2&, L3&...); struct once_flag; template void call_once(once_flag& flag, Callable&& func, Args&&... args); } \end{codeblock} \rSec2[shared.mutex.syn]{Header \tcode{} synopsis} \indexheader{shared_mutex}% \begin{codeblock} namespace std { // \ref{thread.sharedmutex.class}, class \tcode{shared_mutex} class shared_mutex; // \ref{thread.sharedtimedmutex.class}, class \tcode{shared_timed_mutex} class shared_timed_mutex; // \ref{thread.lock.shared}, class template \tcode{shared_lock} template class shared_lock; template void swap(shared_lock& x, shared_lock& y) noexcept; } \end{codeblock} \rSec2[thread.mutex.requirements]{Mutex requirements} \rSec3[thread.mutex.requirements.general]{In general} \pnum A mutex object facilitates protection against data races and allows safe synchronization of data between execution agents\iref{thread.req.lockable}. An execution agent \term{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. \rSec3[thread.mutex.requirements.mutex]{Mutex types} \rSec4[thread.mutex.requirements.mutex.general]{General} \pnum The \defn{mutex types} are the standard library types \tcode{mutex}, \tcode{recursive_mutex}, \tcode{timed_mutex}, \tcode{recursive_timed_mutex}, \tcode{shared_mutex}, and \tcode{shared_timed_mutex}. They meet the requirements set out in \ref{thread.mutex.requirements.mutex}. In this description, \tcode{m} denotes an object of a mutex type. \begin{note} The mutex types meet the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}. \end{note} \pnum The mutex types meet \oldconcept{DefaultConstructible} and \oldconcept{Destructible}. If initialization of an object of a mutex type fails, an exception of type \tcode{system_error} is thrown. The mutex types are neither copyable nor movable. \pnum The error conditions for error codes, if any, reported by member functions of the mutex types are as follows: \begin{itemize} \item \tcode{resource_unavailable_try_again} --- if any native handle type manipulated is not available. \item \tcode{operation_not_permitted} --- if the thread does not have the privilege to perform the operation. \item \tcode{invalid_argument} --- if any native handle type manipulated as part of mutex construction is incorrect. \end{itemize} \pnum 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\iref{intro.multithread}. The lock and unlock operations on a single mutex appears to occur in a single total order. \begin{note} This can be viewed as the modification order\iref{intro.multithread} of the mutex. \end{note} \begin{note} 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} \pnum The expression \tcode{m.lock()} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects If \tcode{m} is of type \tcode{mutex}, \tcode{timed_mutex}, \tcode{shared_mutex}, or \tcode{shared_timed_mutex}, the calling thread does not own the mutex. \pnum \indextext{block (execution)}% \effects Blocks the calling thread until ownership of the mutex can be obtained for the calling thread. \pnum \sync Prior \tcode{unlock()} operations on the same object \term{synchronize with}\iref{intro.multithread} this operation. \pnum \ensures The calling thread owns the mutex. \pnum \returntype \keyword{void}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if the thread does not have the privilege to perform the operation. \item \tcode{resource_deadlock_would_occur} --- if the implementation detects that a deadlock would occur. \end{itemize} \end{itemdescr} \pnum The expression \tcode{m.try_lock()} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects If \tcode{m} is of type \tcode{mutex}, \tcode{timed_mutex}, \tcode{shared_mutex}, or \tcode{shared_timed_mutex}, the calling thread does not own the mutex. \pnum \effects Attempts to obtain ownership of the mutex for the calling thread without blocking. If ownership is not obtained, there is no effect and \tcode{try_lock()} immediately returns. An implementation may fail to obtain the lock even if it is not held by any other thread. \begin{note} This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange\iref{atomics}. \end{note} An implementation should ensure that \tcode{try_lock()} does not consistently return \tcode{false} in the absence of contending mutex acquisitions. \pnum \sync If \tcode{try_lock()} returns \tcode{true}, prior \tcode{unlock()} operations on the same object \term{synchronize with}\iref{intro.multithread} this operation. \begin{note} Since \tcode{lock()} does not synchronize with a failed subsequent \tcode{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} \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if ownership was obtained, otherwise \tcode{false}. \pnum \throws Nothing. \end{itemdescr} \pnum The expression \tcode{m.unlock()} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects The calling thread owns the mutex. \pnum \effects Releases the calling thread's ownership of the mutex. \pnum \returntype \keyword{void}. \pnum \sync This operation synchronizes with\iref{intro.multithread} subsequent lock operations that obtain ownership on the same object. \pnum \throws Nothing. \end{itemdescr} \rSec4[thread.mutex.class]{Class \tcode{mutex}} \indexlibraryglobal{mutex}% \begin{codeblock} 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 = @\impdefnc@; // see~\ref{thread.req.native} native_handle_type native_handle(); // see~\ref{thread.req.native} }; } \end{codeblock} \pnum \indextext{block (execution)}% The class \tcode{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 \tcode{try_lock()}) or block (for \tcode{lock()}) until the owning thread has released ownership with a call to \tcode{unlock()}. \pnum \begin{note} After a thread \tcode{A} has called \tcode{unlock()}, releasing a mutex, it is possible for another thread \tcode{B} to lock the same mutex, observe that it is no longer in use, unlock it, and destroy it, before thread \tcode{A} appears to have returned from its unlock call. Implementations are required to handle such scenarios correctly, as long as thread \tcode{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} \pnum The class \tcode{mutex} meets all of the mutex requirements\iref{thread.mutex.requirements}. It is a standard-layout class\iref{class.prop}. \pnum \begin{note} A program can deadlock if the thread that owns a \tcode{mutex} object calls \tcode{lock()} on that object. If the implementation can detect the deadlock, a \tcode{resource_deadlock_would_occur} error condition might be observed. \end{note} \pnum The behavior of a program is undefined if it destroys a \tcode{mutex} object owned by any thread or a thread terminates while owning a \tcode{mutex} object. \rSec4[thread.mutex.recursive]{Class \tcode{recursive_mutex}} \indexlibraryglobal{recursive_mutex}% \begin{codeblock} 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 = @\impdefnc@; // see~\ref{thread.req.native} native_handle_type native_handle(); // see~\ref{thread.req.native} }; } \end{codeblock} \pnum \indextext{block (execution)}% The class \tcode{recursive_mutex} provides a recursive mutex with exclusive ownership semantics. If one thread owns a \tcode{recursive_mutex} object, attempts by another thread to acquire ownership of that object will fail (for \tcode{try_lock()}) or block (for \tcode{lock()}) until the first thread has completely released ownership. \pnum The class \tcode{recursive_mutex} meets all of the mutex requirements\iref{thread.mutex.requirements}. It is a standard-layout class\iref{class.prop}. \pnum A thread that owns a \tcode{recursive_mutex} object may acquire additional levels of ownership by calling \tcode{lock()} or \tcode{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 \tcode{recursive_mutex} object, additional calls to \tcode{try_lock()} fail, and additional calls to \tcode{lock()} throw an exception of type \tcode{system_error}. A thread shall call \tcode{unlock()} once for each level of ownership acquired by calls to \tcode{lock()} and \tcode{try_lock()}. Only when all levels of ownership have been released may ownership be acquired by another thread. \pnum The behavior of a program is undefined if: \begin{itemize} \item it destroys a \tcode{recursive_mutex} object owned by any thread or \item a thread terminates while owning a \tcode{recursive_mutex} object. \end{itemize} \rSec3[thread.timedmutex.requirements]{Timed mutex types} \rSec4[thread.timedmutex.requirements.general]{General} \pnum The \defn{timed mutex types} are the standard library types \tcode{timed_mutex}, \tcode{recursive_timed_mutex}, and \tcode{shared_timed_mutex}. They meet the requirements set out below. In this description, \tcode{m} denotes an object of a mutex type, \tcode{rel_time} denotes an object of an instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes an object of an instantiation of \tcode{time_point}\iref{time.point}. \begin{note} The timed mutex types meet the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \end{note} \pnum The expression \tcode{m.try_lock_for(rel_time)} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects If \tcode{m} is of type \tcode{timed_mutex} or \tcode{shared_timed_mutex}, the calling thread does not own the mutex. \pnum \effects The function attempts to obtain ownership of the mutex within the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time}. If the time specified by \tcode{rel_time} is less than or equal to \tcode{rel_time.zero()}, the function attempts to obtain ownership without blocking (as if by calling \tcode{try_lock()}). The function returns within the timeout specified by \tcode{rel_time} only if it has obtained ownership of the mutex object. \begin{note} As with \tcode{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} \pnum \sync If \tcode{try_lock_for()} returns \tcode{true}, prior \tcode{unlock()} operations on the same object \term{synchronize with}\iref{intro.multithread} this operation. \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if ownership was obtained, otherwise \tcode{false}. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \pnum The expression \tcode{m.try_lock_until(abs_time)} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects If \tcode{m} is of type \tcode{timed_mutex} or \tcode{shared_timed_mutex}, the calling thread does not own the mutex. \pnum \effects The function attempts to obtain ownership of the mutex. If \tcode{abs_time} has already passed, the function attempts to obtain ownership without blocking (as if by calling \tcode{try_lock()}). The function returns before the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} only if it has obtained ownership of the mutex object. \begin{note} As with \tcode{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} \pnum \sync If \tcode{try_lock_until()} returns \tcode{true}, prior \tcode{unlock()} operations on the same object \term{synchronize with}\iref{intro.multithread} this operation. \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if ownership was obtained, otherwise \tcode{false}. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \rSec4[thread.timedmutex.class]{Class \tcode{timed_mutex}} \indexlibraryglobal{timed_mutex}% \begin{codeblock} 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 bool try_lock_for(const chrono::duration& rel_time); template bool try_lock_until(const chrono::time_point& abs_time); void unlock(); using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} native_handle_type native_handle(); // see~\ref{thread.req.native} }; } \end{codeblock} \pnum \indextext{block (execution)}% The class \tcode{timed_mutex} provides a non-recursive mutex with exclusive ownership semantics. If one thread owns a \tcode{timed_mutex} object, attempts by another thread to acquire ownership of that object will fail (for \tcode{try_lock()}) or block (for \tcode{lock()}, \tcode{try_lock_for()}, and \tcode{try_lock_until()}) until the owning thread has released ownership with a call to \tcode{unlock()} or the call to \tcode{try_lock_for()} or \tcode{try_lock_until()} times out (having failed to obtain ownership). \pnum The class \tcode{timed_mutex} meets all of the timed mutex requirements\iref{thread.timedmutex.requirements}. It is a standard-layout class\iref{class.prop}. \pnum The behavior of a program is undefined if: \begin{itemize} \item it destroys a \tcode{timed_mutex} object owned by any thread, \item a thread that owns a \tcode{timed_mutex} object calls \tcode{lock()}, \tcode{try_lock()}, \tcode{try_lock_for()}, or \tcode{try_lock_until()} on that object, or \item a thread terminates while owning a \tcode{timed_mutex} object. \end{itemize} \rSec4[thread.timedmutex.recursive]{Class \tcode{recursive_timed_mutex}} \indexlibraryglobal{recursive_timed_mutex}% \begin{codeblock} 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 bool try_lock_for(const chrono::duration& rel_time); template bool try_lock_until(const chrono::time_point& abs_time); void unlock(); using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} native_handle_type native_handle(); // see~\ref{thread.req.native} }; } \end{codeblock} \pnum \indextext{block (execution)}% The class \tcode{recursive_timed_mutex} provides a recursive mutex with exclusive ownership semantics. If one thread owns a \tcode{recursive_timed_mutex} object, attempts by another thread to acquire ownership of that object will fail (for \tcode{try_lock()}) or block (for \tcode{lock()}, \tcode{try_lock_for()}, and \tcode{try_lock_until()}) until the owning thread has completely released ownership or the call to \tcode{try_lock_for()} or \tcode{try_lock_until()} times out (having failed to obtain ownership). \pnum The class \tcode{recursive_timed_mutex} meets all of the timed mutex requirements\iref{thread.timedmutex.requirements}. It is a standard-layout class\iref{class.prop}. \pnum A thread that owns a \tcode{recursive_timed_mutex} object may acquire additional levels of ownership by calling \tcode{lock()}, \tcode{try_lock()}, \tcode{try_lock_for()}, or \tcode{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 \tcode{recursive_timed_mutex} object, additional calls to \tcode{try_lock()}, \tcode{try_lock_for()}, or \tcode{try_lock_until()} fail, and additional calls to \tcode{lock()} throw an exception of type \tcode{system_error}. A thread shall call \tcode{unlock()} once for each level of ownership acquired by calls to \tcode{lock()}, \tcode{try_lock()}, \tcode{try_lock_for()}, and \tcode{try_lock_until()}. Only when all levels of ownership have been released may ownership of the object be acquired by another thread. \pnum The behavior of a program is undefined if: \begin{itemize} \item it destroys a \tcode{recursive_timed_mutex} object owned by any thread, or \item a thread terminates while owning a \tcode{recursive_timed_mutex} object. \end{itemize} \rSec3[thread.sharedmutex.requirements]{Shared mutex types} \rSec4[thread.sharedmutex.requirements.general]{General} \pnum The standard library types \tcode{shared_mutex} and \tcode{shared_timed_mutex} are \defn{shared mutex types}. Shared mutex types meet the requirements of mutex types\iref{thread.mutex.requirements.mutex} and additionally meet the requirements set out below. In this description, \tcode{m} denotes an object of a shared mutex type. \begin{note} The shared mutex types meet the \oldconcept{SharedLockable} requirements\iref{thread.req.lockable.shared}. \end{note} \pnum \indextext{block (execution)}% In addition to the exclusive lock ownership mode specified in~\ref{thread.mutex.requirements.mutex}, shared mutex types provide a \defn{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. \pnum The expression \tcode{m.lock_shared()} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects The calling thread has no ownership of the mutex. \pnum \indextext{block (execution)}% \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. \pnum \sync Prior \tcode{unlock()} operations on the same object synchronize with\iref{intro.multithread} this operation. \pnum \ensures The calling thread has a shared lock on the mutex. \pnum \returntype \keyword{void}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if the thread does not have the privilege to perform the operation. \item \tcode{resource_deadlock_would_occur} --- if the implementation detects that a deadlock would occur. \end{itemize} \end{itemdescr} \pnum The expression \tcode{m.unlock_shared()} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects The calling thread holds a shared lock on the mutex. \pnum \effects Releases a shared lock on the mutex held by the calling thread. \pnum \returntype \keyword{void}. \pnum \sync This operation synchronizes with\iref{intro.multithread} subsequent \tcode{lock()} operations that obtain ownership on the same object. \pnum \throws Nothing. \end{itemdescr} \pnum The expression \tcode{m.try_lock_shared()} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects The calling thread has no ownership of the mutex. \pnum \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 \tcode{try_lock_shared()} immediately returns. An implementation may fail to obtain the lock even if it is not held by any other thread. \pnum \sync If \tcode{try_lock_shared()} returns \tcode{true}, prior \tcode{unlock()} operations on the same object synchronize with\iref{intro.multithread} this operation. \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if the shared lock was acquired, otherwise \tcode{false}. \pnum \throws Nothing. \end{itemdescr} \rSec4[thread.sharedmutex.class]{Class \tcode{shared_mutex}} \indexlibraryglobal{shared_mutex}% \begin{codeblock} 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 = @\impdefnc@; // see~\ref{thread.req.native} native_handle_type native_handle(); // see~\ref{thread.req.native} }; } \end{codeblock} \pnum The class \tcode{shared_mutex} provides a non-recursive mutex with shared ownership semantics. \pnum The class \tcode{shared_mutex} meets all of the shared mutex requirements\iref{thread.sharedmutex.requirements}. It is a standard-layout class\iref{class.prop}. \pnum The behavior of a program is undefined if: \begin{itemize} \item it destroys a \tcode{shared_mutex} object owned by any thread, \item a thread attempts to recursively gain any ownership of a \tcode{shared_mutex}, or \item a thread terminates while possessing any ownership of a \tcode{shared_mutex}. \end{itemize} \pnum \tcode{shared_mutex} may be a synonym for \tcode{shared_timed_mutex}. \rSec3[thread.sharedtimedmutex.requirements]{Shared timed mutex types} \rSec4[thread.sharedtimedmutex.requirements.general]{General} \pnum The standard library type \tcode{shared_timed_mutex} is a \defn{shared timed mutex type}. Shared timed mutex types meet the requirements of timed mutex types\iref{thread.timedmutex.requirements}, shared mutex types\iref{thread.sharedmutex.requirements}, and additionally meet the requirements set out below. In this description, \tcode{m} denotes an object of a shared timed mutex type, \tcode{rel_time} denotes an object of an instantiation of \tcode{duration}\iref{time.duration}, and \tcode{abs_time} denotes an object of an instantiation of \tcode{time_point}\iref{time.point}. \begin{note} The shared timed mutex types meet the \oldconcept{SharedTimedLockable} requirements\iref{thread.req.lockable.shared.timed}. \end{note} \pnum The expression \tcode{m.try_lock_shared_for(rel_time)} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects The calling thread has no ownership of the mutex. \pnum \effects Attempts to obtain shared lock ownership for the calling thread within the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time}. If the time specified by \tcode{rel_time} is less than or equal to \tcode{rel_time.zero()}, the function attempts to obtain ownership without blocking (as if by calling \tcode{try_lock_shared()}). The function returns within the timeout specified by \tcode{rel_time} only if it has obtained shared ownership of the mutex object. \begin{note} As with \tcode{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. \pnum \sync If \tcode{try_lock_shared_for()} returns \tcode{true}, prior \tcode{unlock()} operations on the same object synchronize with\iref{intro.multithread} this operation. \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if the shared lock was acquired, otherwise \tcode{false}. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \pnum The expression \tcode{m.try_lock_shared_until(abs_time)} is well-formed and has the following semantics: \begin{itemdescr} \pnum \expects The calling thread has no ownership of the mutex. \pnum \effects The function attempts to obtain shared ownership of the mutex. If \tcode{abs_time} has already passed, the function attempts to obtain shared ownership without blocking (as if by calling \tcode{try_lock_shared()}). The function returns before the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} only if it has obtained shared ownership of the mutex object. \begin{note} As with \tcode{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. \pnum \sync If \tcode{try_lock_shared_until()} returns \tcode{true}, prior \tcode{unlock()} operations on the same object synchronize with\iref{intro.multithread} this operation. \pnum \returntype \tcode{bool}. \pnum \returns \tcode{true} if the shared lock was acquired, otherwise \tcode{false}. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \rSec4[thread.sharedtimedmutex.class]{Class \tcode{shared_timed_mutex}} \indexlibraryglobal{shared_timed_mutex}% \begin{codeblock} 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 bool try_lock_for(const chrono::duration& rel_time); template bool try_lock_until(const chrono::time_point& abs_time); void unlock(); // shared ownership void lock_shared(); // blocking bool try_lock_shared(); template bool try_lock_shared_for(const chrono::duration& rel_time); template bool try_lock_shared_until(const chrono::time_point& abs_time); void unlock_shared(); }; } \end{codeblock} \pnum The class \tcode{shared_timed_mutex} provides a non-recursive mutex with shared ownership semantics. \pnum The class \tcode{shared_timed_mutex} meets all of the shared timed mutex requirements\iref{thread.sharedtimedmutex.requirements}. It is a standard-layout class\iref{class.prop}. \pnum The behavior of a program is undefined if: \begin{itemize} \item it destroys a \tcode{shared_timed_mutex} object owned by any thread, \item a thread attempts to recursively gain any ownership of a \tcode{shared_timed_mutex}, or \item a thread terminates while possessing any ownership of a \tcode{shared_timed_mutex}. \end{itemize} \rSec2[thread.lock]{Locks} \rSec3[thread.lock.general]{General} \pnum A \term{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 \term{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. \begin{note} Locks are intended to ease the burden of unlocking the lockable object under both normal and exceptional circumstances. \end{note} \pnum Some lock constructors take tag types which describe what should be done with the lockable object during the lock's construction. \indexlibraryglobal{defer_lock_t}% \indexlibraryglobal{try_to_lock_t}% \indexlibraryglobal{adopt_lock_t}% \indexlibraryglobal{defer_lock}% \indexlibraryglobal{try_to_lock}% \indexlibraryglobal{adopt_lock}% \begin{codeblock} 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 { }; } \end{codeblock} \rSec3[thread.lock.guard]{Class template \tcode{lock_guard}} \indexlibraryglobal{lock_guard}% \begin{codeblock} namespace std { template 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 lock_guard&) = delete; lock_guard& operator=(const lock_guard&) = delete; private: mutex_type& pm; // \expos }; } \end{codeblock} \pnum An object of type \tcode{lock_guard} controls the ownership of a lockable object within a scope. A \tcode{lock_guard} object maintains ownership of a lockable object throughout the \tcode{lock_guard} object's lifetime\iref{basic.life}. The behavior of a program is undefined if the lockable object referenced by \tcode{pm} does not exist for the entire lifetime of the \tcode{lock_guard} object. The supplied \tcode{Mutex} type shall meet the \oldconcept{BasicLockable} requirements\iref{thread.req.lockable.basic}. \indexlibraryctor{lock_guard}% \begin{itemdecl} explicit lock_guard(mutex_type& m); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{pm} with \tcode{m}. Calls \tcode{m.lock()}. \end{itemdescr} \indexlibraryctor{lock_guard}% \begin{itemdecl} lock_guard(mutex_type& m, adopt_lock_t); \end{itemdecl} \begin{itemdescr} \pnum \expects The calling thread holds a non-shared lock on \tcode{m}. \pnum \effects Initializes \tcode{pm} with \tcode{m}. \pnum \throws Nothing. \end{itemdescr} \indexlibrarydtor{lock_guard}% \begin{itemdecl} ~lock_guard(); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{pm.unlock()} \end{itemdescr} \rSec3[thread.lock.scoped]{Class template \tcode{scoped_lock}} \indexlibraryglobal{scoped_lock}% \begin{codeblock} namespace std { template class scoped_lock { public: using mutex_type = @\seebelow@; // Only if \tcode{sizeof...(MutexTypes) == 1} is \tcode{true} explicit scoped_lock(MutexTypes&... m); explicit scoped_lock(adopt_lock_t, MutexTypes&... m); ~scoped_lock(); scoped_lock(const scoped_lock&) = delete; scoped_lock& operator=(const scoped_lock&) = delete; private: tuple pm; // \expos }; } \end{codeblock} \pnum An object of type \tcode{scoped_lock} controls the ownership of lockable objects within a scope. A \tcode{scoped_lock} object maintains ownership of lockable objects throughout the \tcode{scoped_lock} object's lifetime\iref{basic.life}. The behavior of a program is undefined if the lockable objects referenced by \tcode{pm} do not exist for the entire lifetime of the \tcode{scoped_lock} object. \begin{itemize} \item If \tcode{sizeof...(MutexTypes)} is one, let \tcode{Mutex} denote the sole type constituting the pack \tcode{MutexTypes}. \tcode{Mutex} shall meet the \oldconcept{BasicLockable} requirements\iref{thread.req.lockable.basic}. The member \grammarterm{typedef-name} \tcode{mutex_type} denotes the same type as \tcode{Mutex}. \item Otherwise, all types in the template parameter pack \tcode{MutexTypes} shall meet the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req} and there is no member \tcode{mutex_type}. \end{itemize} \indexlibraryctor{scoped_lock}% \begin{itemdecl} explicit scoped_lock(MutexTypes&... m); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{pm} with \tcode{tie(m...)}. Then if \tcode{sizeof...(MutexTypes)} is \tcode{0}, no effects. Otherwise if \tcode{sizeof...(MutexTypes)} is \tcode{1}, then \tcode{m.lock()}. Otherwise, \tcode{lock(m...)}. \end{itemdescr} \indexlibraryctor{scoped_lock}% \begin{itemdecl} explicit scoped_lock(adopt_lock_t, MutexTypes&... m); \end{itemdecl} \begin{itemdescr} \pnum \expects The calling thread holds a non-shared lock on each element of \tcode{m}. \pnum \effects Initializes \tcode{pm} with \tcode{tie(m...)}. \pnum \throws Nothing. \end{itemdescr} \indexlibrarydtor{scoped_lock}% \begin{itemdecl} ~scoped_lock(); \end{itemdecl} \begin{itemdescr} \pnum \effects For all \tcode{i} in \range{0}{sizeof...(MutexTypes)}, \tcode{get(pm).unlock()}. \end{itemdescr} \rSec3[thread.lock.unique]{Class template \tcode{unique_lock}} \rSec4[thread.lock.unique.general]{General} \indexlibraryglobal{unique_lock}% \begin{codeblock} namespace std { template class unique_lock { public: using mutex_type = Mutex; // \ref{thread.lock.unique.cons}, construct/copy/destroy unique_lock() noexcept; explicit unique_lock(mutex_type& m); unique_lock(mutex_type& m, defer_lock_t) noexcept; unique_lock(mutex_type& m, try_to_lock_t); unique_lock(mutex_type& m, adopt_lock_t); template unique_lock(mutex_type& m, const chrono::time_point& abs_time); template unique_lock(mutex_type& m, const chrono::duration& rel_time); ~unique_lock(); unique_lock(const unique_lock&) = delete; unique_lock& operator=(const unique_lock&) = delete; unique_lock(unique_lock&& u) noexcept; unique_lock& operator=(unique_lock&& u); // \ref{thread.lock.unique.locking}, locking void lock(); bool try_lock(); template bool try_lock_for(const chrono::duration& rel_time); template bool try_lock_until(const chrono::time_point& abs_time); void unlock(); // \ref{thread.lock.unique.mod}, modifiers void swap(unique_lock& u) noexcept; mutex_type* release() noexcept; // \ref{thread.lock.unique.obs}, observers bool owns_lock() const noexcept; explicit operator bool () const noexcept; mutex_type* mutex() const noexcept; private: mutex_type* pm; // \expos bool owns; // \expos }; } \end{codeblock} \pnum An object of type \tcode{unique_lock} controls the ownership of a lockable object within a scope. Ownership of the lockable object may be acquired at construction or after construction, and may be transferred, after acquisition, to another \tcode{unique_lock} object. Objects of type \tcode{unique_lock} are not copyable but are movable. The behavior of a program is undefined if the contained pointer \tcode{pm} is not null and the lockable object pointed to by \tcode{pm} does not exist for the entire remaining lifetime\iref{basic.life} of the \tcode{unique_lock} object. The supplied \tcode{Mutex} type shall meet the \oldconcept{BasicLockable} requirements\iref{thread.req.lockable.basic}. \pnum \begin{note} \tcode{unique_lock} meets the \oldconcept{BasicLockable} requirements. If \tcode{Mutex} meets the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}, \tcode{unique_lock} also meets the \oldconcept{Lockable} requirements; if \tcode{Mutex} meets the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}, \tcode{unique_lock} also meets the \oldconcept{TimedLockable} requirements. \end{note} \rSec4[thread.lock.unique.cons]{Constructors, destructor, and assignment} \indexlibraryctor{unique_lock}% \begin{itemdecl} unique_lock() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{pm == nullptr} and \tcode{owns == false}. \end{itemdescr} \indexlibraryctor{unique_lock}% \begin{itemdecl} explicit unique_lock(mutex_type& m); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{m.lock()}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. \end{itemdescr} \indexlibraryctor{unique_lock}% \begin{itemdecl} unique_lock(mutex_type& m, defer_lock_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == false}. \end{itemdescr} \indexlibraryctor{unique_lock}% \begin{itemdecl} unique_lock(mutex_type& m, try_to_lock_t); \end{itemdecl} \begin{itemdescr} \pnum \expects The supplied \tcode{Mutex} type meets the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}. \pnum \effects Calls \tcode{m.try_lock()}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{m.try_lock()}. \end{itemdescr} \indexlibraryctor{unique_lock}% \begin{itemdecl} unique_lock(mutex_type& m, adopt_lock_t); \end{itemdecl} \begin{itemdescr} \pnum \expects The calling thread holds a non-shared lock on \tcode{m}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. \pnum \throws Nothing. \end{itemdescr} \indexlibraryctor{unique_lock}% \begin{itemdecl} template unique_lock(mutex_type& m, const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum \expects The supplied \tcode{Mutex} type meets the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \pnum \effects Calls \tcode{m.try_lock_until(abs_time)}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{m.try_lock_until(abs_time)}. \end{itemdescr} \indexlibraryctor{unique_lock}% \begin{itemdecl} template unique_lock(mutex_type& m, const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum \expects The supplied \tcode{Mutex} type meets the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \pnum \effects Calls \tcode{m.try_lock_for(rel_time)}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{m.try_lock_for(rel_time)}. \end{itemdescr} \indexlibraryctor{unique_lock}% \begin{itemdecl} unique_lock(unique_lock&& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{pm == u_p.pm} and \tcode{owns == u_p.owns} (where \tcode{u_p} is the state of \tcode{u} just prior to this construction), \tcode{u.pm == 0} and \tcode{u.owns == false}. \end{itemdescr} \indexlibrarymember{operator=}{unique_lock}% \begin{itemdecl} unique_lock& operator=(unique_lock&& u); \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{owns} calls \tcode{pm->unlock()}. \pnum \ensures \tcode{pm == u_p.pm} and \tcode{owns == u_p.owns} (where \tcode{u_p} is the state of \tcode{u} just prior to this construction), \tcode{u.pm == 0} and \tcode{u.owns == false}. \pnum \begin{note} With a recursive mutex it is possible for both \tcode{*this} and \tcode{u} to own the same mutex before the assignment. In this case, \tcode{*this} will own the mutex after the assignment and \tcode{u} will not. \end{note} \pnum \throws Nothing. \end{itemdescr} \indexlibrarydtor{unique_lock}% \begin{itemdecl} ~unique_lock(); \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{owns} calls \tcode{pm->unlock()}. \end{itemdescr} \rSec4[thread.lock.unique.locking]{Locking} \indexlibrarymember{lock}{unique_lock}% \begin{itemdecl} void lock(); \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{pm->lock()}. \pnum \ensures \tcode{owns == true}. \pnum \throws Any exception thrown by \tcode{pm->lock()}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. \item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{try_lock}{unique_lock}% \begin{itemdecl} bool try_lock(); \end{itemdecl} \begin{itemdescr} \pnum \expects The supplied \tcode{Mutex} meets the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}. \pnum \effects As if by \tcode{pm->try_lock()}. \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by \tcode{pm->try_lock()}. \pnum \returns The value returned by \tcode{pm->try_lock()}. \pnum \throws Any exception thrown by \tcode{pm->try_lock()}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. \item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{try_lock_until}{unique_lock}% \begin{itemdecl} template bool try_lock_until(const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum \expects The supplied \tcode{Mutex} type meets the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \pnum \effects As if by \tcode{pm->try_lock_until(abs_time)}. \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by \tcode{pm->try_lock_until(abs_time)}. \pnum \returns The value returned by \tcode{pm->try_lock_until(abs_time)}. \pnum \throws Any exception thrown by \tcode{pm->try_lock_until(abstime)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. \item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{try_lock_for}{unique_lock}% \begin{itemdecl} template bool try_lock_for(const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum \expects The supplied \tcode{Mutex} type meets the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \pnum \effects As if by \tcode{pm->try_lock_for(rel_time)}. \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by \tcode{pm->try_lock_for(rel_time)}. \pnum \returns The value returned by \tcode{pm->try_lock_for(rel_time)}. \pnum \throws Any exception thrown by \tcode{pm->try_lock_for(rel_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. \item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{unlock}{unique_lock}% \begin{itemdecl} void unlock(); \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{pm->unlock()}. \pnum \ensures \tcode{owns == false}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if on entry \tcode{owns} is \tcode{false}. \end{itemize} \end{itemdescr} \rSec4[thread.lock.unique.mod]{Modifiers} \indexlibrarymember{swap}{unique_lock}% \begin{itemdecl} void swap(unique_lock& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Swaps the data members of \tcode{*this} and \tcode{u}. \end{itemdescr} \indexlibrarymember{release}{unique_lock}% \begin{itemdecl} mutex_type* release() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{pm == 0} and \tcode{owns == false}. \pnum \returns The previous value of \tcode{pm}. \end{itemdescr} \indexlibrarymember{swap}{unique_lock}% \begin{itemdecl} template void swap(unique_lock& x, unique_lock& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{x.swap(y)}. \end{itemdescr} \rSec4[thread.lock.unique.obs]{Observers} \indexlibrarymember{owns_lock}{unique_lock}% \begin{itemdecl} bool owns_lock() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{owns}. \end{itemdescr} \indexlibrarymember{operator bool}{unique_lock}% \begin{itemdecl} explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{owns}. \end{itemdescr} \indexlibrarymember{mutex}{unique_lock}% \begin{itemdecl} mutex_type *mutex() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{pm}. \end{itemdescr} \rSec3[thread.lock.shared]{Class template \tcode{shared_lock}} \rSec4[thread.lock.shared.general]{General} \indexlibraryglobal{shared_lock}% \begin{codeblock} namespace std { template class shared_lock { public: using mutex_type = Mutex; // \ref{thread.lock.shared.cons}, construct/copy/destroy shared_lock() noexcept; explicit shared_lock(mutex_type& m); // blocking shared_lock(mutex_type& m, defer_lock_t) noexcept; shared_lock(mutex_type& m, try_to_lock_t); shared_lock(mutex_type& m, adopt_lock_t); template shared_lock(mutex_type& m, const chrono::time_point& abs_time); template shared_lock(mutex_type& m, const chrono::duration& rel_time); ~shared_lock(); shared_lock(const shared_lock&) = delete; shared_lock& operator=(const shared_lock&) = delete; shared_lock(shared_lock&& u) noexcept; shared_lock& operator=(shared_lock&& u) noexcept; // \ref{thread.lock.shared.locking}, locking void lock(); // blocking bool try_lock(); template bool try_lock_for(const chrono::duration& rel_time); template bool try_lock_until(const chrono::time_point& abs_time); void unlock(); // \ref{thread.lock.shared.mod}, modifiers void swap(shared_lock& u) noexcept; mutex_type* release() noexcept; // \ref{thread.lock.shared.obs}, observers bool owns_lock() const noexcept; explicit operator bool () const noexcept; mutex_type* mutex() const noexcept; private: mutex_type* pm; // \expos bool owns; // \expos }; } \end{codeblock} \pnum An object of type \tcode{shared_lock} controls the shared ownership of a lockable object within a scope. Shared ownership of the lockable object may be acquired at construction or after construction, and may be transferred, after acquisition, to another \tcode{shared_lock} object. Objects of type \tcode{shared_lock} are not copyable but are movable. The behavior of a program is undefined if the contained pointer \tcode{pm} is not null and the lockable object pointed to by \tcode{pm} does not exist for the entire remaining lifetime\iref{basic.life} of the \tcode{shared_lock} object. The supplied \tcode{Mutex} type shall meet the \oldconcept{SharedLockable} requirements\iref{thread.req.lockable.shared}. \pnum \begin{note} \tcode{shared_lock} meets the \oldconcept{Lockable} requirements\iref{thread.req.lockable.req}. If \tcode{Mutex} meets the \oldconcept{Shared\-TimedLockable} requirements\iref{thread.req.lockable.shared.timed}, \tcode{shared_lock} also meets the \oldconcept{TimedLockable} requirements\iref{thread.req.lockable.timed}. \end{note} \rSec4[thread.lock.shared.cons]{Constructors, destructor, and assignment} \indexlibraryctor{shared_lock}% \begin{itemdecl} shared_lock() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{pm == nullptr} and \tcode{owns == false}. \end{itemdescr} \indexlibraryctor{shared_lock}% \begin{itemdecl} explicit shared_lock(mutex_type& m); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{m.lock_shared()}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. \end{itemdescr} \indexlibraryctor{shared_lock}% \begin{itemdecl} shared_lock(mutex_type& m, defer_lock_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == false}. \end{itemdescr} \indexlibraryctor{shared_lock}% \begin{itemdecl} shared_lock(mutex_type& m, try_to_lock_t); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{m.try_lock_shared()}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == res} where \tcode{res} is the value returned by the call to \tcode{m.try_lock_shared()}. \end{itemdescr} \indexlibraryctor{shared_lock}% \begin{itemdecl} shared_lock(mutex_type& m, adopt_lock_t); \end{itemdecl} \begin{itemdescr} \pnum \expects The calling thread holds a shared lock on \tcode{m}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == true}. \end{itemdescr} \indexlibraryctor{shared_lock}% \begin{itemdecl} template shared_lock(mutex_type& m, const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{Mutex} meets the \oldconcept{SharedTimedLockable} requirements\iref{thread.req.lockable.shared.timed}. \pnum \effects Calls \tcode{m.try_lock_shared_until(abs_time)}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == res} where \tcode{res} is the value returned by the call to \tcode{m.try_lock_shared_until(abs_time)}. \end{itemdescr} \indexlibraryctor{shared_lock}% \begin{itemdecl} template shared_lock(mutex_type& m, const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{Mutex} meets the \oldconcept{SharedTimedLockable} requirements\iref{thread.req.lockable.shared.timed}. \pnum \effects Calls \tcode{m.try_lock_shared_for(rel_time)}. \pnum \ensures \tcode{pm == addressof(m)} and \tcode{owns == res} where \tcode{res} is the value returned by the call to \tcode{m.try_lock_shared_for(rel_time)}. \end{itemdescr} \indexlibrarydtor{shared_lock}% \begin{itemdecl} ~shared_lock(); \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{owns} calls \tcode{pm->unlock_shared()}. \end{itemdescr} \indexlibraryctor{shared_lock}% \begin{itemdecl} shared_lock(shared_lock&& sl) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{pm == sl_p.pm} and \tcode{owns == sl_p.owns} (where \tcode{sl_p} is the state of \tcode{sl} just prior to this construction), \tcode{sl.pm == nullptr} and \tcode{sl.owns == false}. \end{itemdescr} \indexlibrarymember{operator=}{shared_lock}% \begin{itemdecl} shared_lock& operator=(shared_lock&& sl) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{owns} calls \tcode{pm->unlock_shared()}. \pnum \ensures \tcode{pm == sl_p.pm} and \tcode{owns == sl_p.owns} (where \tcode{sl_p} is the state of \tcode{sl} just prior to this assignment), \tcode{sl.pm == nullptr} and \tcode{sl.owns == false}. \end{itemdescr} \rSec4[thread.lock.shared.locking]{Locking} \indexlibrarymember{lock}{shared_lock}% \begin{itemdecl} void lock(); \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{pm->lock_shared()}. \pnum \ensures \tcode{owns == true}. \pnum \throws Any exception thrown by \tcode{pm->lock_shared()}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. \item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{try_lock}{shared_lock}% \begin{itemdecl} bool try_lock(); \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{pm->try_lock_shared()}. \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{pm->try_lock_shared()}. \pnum \returns The value returned by the call to \tcode{pm->try_lock_shared()}. \pnum \throws Any exception thrown by \tcode{pm->try_lock_shared()}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. \item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{try_lock_until}{shared_lock}% \begin{itemdecl} template bool try_lock_until(const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{Mutex} meets the \oldconcept{SharedTimedLockable} requirements\iref{thread.req.lockable.shared.timed}. \pnum \effects As if by \tcode{pm->try_lock_shared_until(abs_time)}. \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{pm->try_lock_shared_until(abs_time)}. \pnum \returns The value returned by the call to \tcode{pm->try_lock_shared_until(abs_time)}. \pnum \throws Any exception thrown by \tcode{pm->try_lock_shared_until(abs_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. \item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{try_lock_for}{shared_lock}% \begin{itemdecl} template bool try_lock_for(const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{Mutex} meets the \oldconcept{SharedTimedLockable} requirements\iref{thread.req.lockable.shared.timed}. \pnum \effects As if by \tcode{pm->try_lock_shared_for(rel_time)}. \pnum \ensures \tcode{owns == res}, where \tcode{res} is the value returned by the call to \tcode{pm->try_lock_shared_for(rel_time)}. \pnum \returns The value returned by the call to \tcode{pm->try_lock_shared_for(rel_time)}. \pnum \throws Any exception thrown by \tcode{pm->try_lock_shared_for(rel_time)}. \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if \tcode{pm} is \keyword{nullptr}. \item \tcode{resource_deadlock_would_occur} --- if on entry \tcode{owns} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{unlock}{shared_lock}% \begin{itemdecl} void unlock(); \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{pm->unlock_shared()}. \pnum \ensures \tcode{owns == false}. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{operation_not_permitted} --- if on entry \tcode{owns} is \tcode{false}. \end{itemize} \end{itemdescr} \rSec4[thread.lock.shared.mod]{Modifiers} \indexlibrarymember{swap}{shared_lock}% \begin{itemdecl} void swap(shared_lock& sl) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Swaps the data members of \tcode{*this} and \tcode{sl}. \end{itemdescr} \indexlibrarymember{release}{shared_lock}% \begin{itemdecl} mutex_type* release() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{pm == nullptr} and \tcode{owns == false}. \pnum \returns The previous value of \tcode{pm}. \end{itemdescr} \indexlibrarymember{swap}{shared_lock}% \begin{itemdecl} template void swap(shared_lock& x, shared_lock& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{x.swap(y)}. \end{itemdescr} \rSec4[thread.lock.shared.obs]{Observers} \indexlibrarymember{owns_lock}{shared_lock}% \begin{itemdecl} bool owns_lock() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{owns}. \end{itemdescr} \indexlibrarymember{operator bool}{shared_lock}% \begin{itemdecl} explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{owns}. \end{itemdescr} \indexlibrarymember{mutex}{shared_lock}% \begin{itemdecl} mutex_type* mutex() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{pm}. \end{itemdescr} \rSec2[thread.lock.algorithm]{Generic locking algorithms} \indexlibraryglobal{try_lock}% \begin{itemdecl} template int try_lock(L1&, L2&, L3&...); \end{itemdecl} \begin{itemdescr} \pnum \expects Each template parameter type meets the \oldconcept{Lockable} requirements. \begin{note} The \tcode{unique_lock} class template meets these requirements when suitably instantiated. \end{note} \pnum \effects Calls \tcode{try_lock()} for each argument in order beginning with the first until all arguments have been processed or a call to \tcode{try_lock()} fails, either by returning \tcode{false} or by throwing an exception. If a call to \tcode{try_lock()} fails, \tcode{unlock()} is called for all prior arguments with no further calls to \tcode{try_lock()}. \pnum \returns \tcode{-1} if all calls to \tcode{try_lock()} returned \tcode{true}, otherwise a zero-based index value that indicates the argument for which \tcode{try_lock()} returned \tcode{false}. \end{itemdescr} \indexlibraryglobal{lock}% \begin{itemdecl} template void lock(L1&, L2&, L3&...); \end{itemdecl} \begin{itemdescr} \pnum \expects Each template parameter type meets the \oldconcept{Lockable} requirements. \begin{note} The \tcode{unique_lock} class template meets these requirements when suitably instantiated. \end{note} \pnum \effects All arguments are locked via a sequence of calls to \tcode{lock()}, \tcode{try_lock()}, or \tcode{unlock()} on each argument. The sequence of calls does not result in deadlock, but is otherwise unspecified. \begin{note} A deadlock avoidance algorithm such as try-and-back-off can be used, but the specific algorithm is not specified to avoid over-constraining implementations. \end{note} If a call to \tcode{lock()} or \tcode{try_lock()} throws an exception, \tcode{unlock()} is called for any argument that had been locked by a call to \tcode{lock()} or \tcode{try_lock()}. \end{itemdescr} \rSec2[thread.once]{Call once} \rSec3[thread.once.onceflag]{Struct \tcode{once_flag}} \indexlibraryglobal{once_flag}% \begin{codeblock} namespace std { struct once_flag { constexpr once_flag() noexcept; once_flag(const once_flag&) = delete; once_flag& operator=(const once_flag&) = delete; }; } \end{codeblock} \pnum The class \tcode{once_flag} is an opaque data structure that \tcode{call_once} uses to initialize data without causing a data race or deadlock. \indexlibraryglobal{once_flag}% \begin{itemdecl} constexpr once_flag() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \sync The construction of a \tcode{once_flag} object is not synchronized. \pnum \ensures The object's internal state is set to indicate to an invocation of \tcode{call_once} with the object as its initial argument that no function has been called. \end{itemdescr} \rSec3[thread.once.callonce]{Function \tcode{call_once}} \indexlibraryglobal{call_once}% \begin{itemdecl} template void call_once(once_flag& flag, Callable&& func, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{is_invocable_v} is \tcode{true}. \pnum \effects An execution of \tcode{call_once} that does not call its \tcode{func} is a \term{passive} execution. An execution of \tcode{call_once} that calls its \tcode{func} is an \term{active} execution. An active execution calls \tcode{\placeholdernc{INVOKE}(\brk{}% std::forward(func), std::forward(args)...)}\iref{func.require}. If such a call to \tcode{func} throws an exception the execution is \term{exceptional}, otherwise it is \term{returning}. An exceptional execution propagates the exception to the caller of \tcode{call_once}. Among all executions of \tcode{call_once} for any given \tcode{once_flag}: at most one is a returning execution; if there is a returning execution, it is the last active execution; and there are passive executions only if there is a returning execution. \begin{note} Passive executions allow other threads to reliably observe the results produced by the earlier returning execution. \end{note} \pnum \sync For any given \tcode{once_flag}: all active executions occur in a total order; completion of an active execution synchronizes with\iref{intro.multithread} the start of the next one in this total order; and the returning execution synchronizes with the return from all passive executions. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}, or any exception thrown by \tcode{func}. \pnum \begin{example} \begin{codeblock} // global flag, regular function void init(); std::once_flag flag; void f() { std::call_once(flag, init); } // function static flag, function object struct initializer { void operator()(); }; void g() { static std::once_flag flag2; std::call_once(flag2, initializer()); } // object flag, member function class information { std::once_flag verified; void verifier(); public: void verify() { std::call_once(verified, &information::verifier, *this); } }; \end{codeblock} \end{example} \end{itemdescr} \rSec1[thread.condition]{Condition variables} \rSec2[thread.condition.general]{General} \pnum Condition variables provide synchronization primitives used to block a thread until notified by some other thread that some condition is met or until a system time is reached. Class \tcode{condition_variable} provides a condition variable that can only wait on an object of type \tcode{unique_lock}, allowing the implementation to be more efficient. Class \tcode{condition_variable_any} provides a general condition variable that can wait on objects of user-supplied lock types. \pnum Condition variables permit concurrent invocation of the \tcode{wait}, \tcode{wait_for}, \tcode{wait_until}, \tcode{notify_one} and \tcode{notify_all} member functions. \pnum The executions of \tcode{notify_one} and \tcode{notify_all} are atomic. The executions of \tcode{wait}, \tcode{wait_for}, and \tcode{wait_until} are performed in three atomic parts: \begin{enumerate} \item the release of the mutex and entry into the waiting state; \item the unblocking of the wait; and \item the reacquisition of the lock. \end{enumerate} \pnum The implementation behaves as if all executions of \tcode{notify_one}, \tcode{notify_all}, and each part of the \tcode{wait}, \tcode{wait_for}, and \tcode{wait_until} executions are executed in a single unspecified total order consistent with the ``happens before'' order. \pnum Condition variable construction and destruction need not be synchronized. \rSec2[condition.variable.syn]{Header \tcode{} synopsis} \indexheader{condition_variable}% \indexlibraryglobal{cv_status}% \begin{codeblock} namespace std { // \ref{thread.condition.condvar}, class \tcode{condition_variable} class condition_variable; // \ref{thread.condition.condvarany}, class \tcode{condition_variable_any} class condition_variable_any; // \ref{thread.condition.nonmember}, non-member functions void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); enum class cv_status { no_timeout, timeout }; } \end{codeblock} \rSec2[thread.condition.nonmember]{Non-member functions} \indexlibraryglobal{notify_all_at_thread_exit}% \begin{itemdecl} void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{lk} is locked by the calling thread and either \begin{itemize} \item no other thread is waiting on \tcode{cond}, or \item \tcode{lk.mutex()} returns the same value for each of the lock arguments supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until}) threads. \end{itemize} \pnum \effects Transfers ownership of the lock associated with \tcode{lk} into internal storage and schedules \tcode{cond} to be notified when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. This notification is equivalent to: \begin{codeblock} lk.unlock(); cond.notify_all(); \end{codeblock} \pnum \sync The implied \tcode{lk.unlock()} call is sequenced after the destruction of all objects with thread storage duration associated with the current thread. \pnum \begin{note} The supplied lock is held until the thread exits, which might cause deadlock due to lock ordering issues. \end{note} \pnum \begin{note} It is the user's responsibility to ensure that waiting threads do not erroneously assume that the thread has finished if they experience spurious wakeups. This typically requires that the condition being waited for is satisfied while holding the lock on \tcode{lk}, and that this lock is not released and reacquired prior to calling \tcode{notify_all_at_thread_exit}. \end{note} \end{itemdescr} \rSec2[thread.condition.condvar]{Class \tcode{condition_variable}} \indexlibraryglobal{condition_variable}% \begin{codeblock} namespace std { class condition_variable { public: condition_variable(); ~condition_variable(); condition_variable(const condition_variable&) = delete; condition_variable& operator=(const condition_variable&) = delete; void notify_one() noexcept; void notify_all() noexcept; void wait(unique_lock& lock); template void wait(unique_lock& lock, Predicate pred); template cv_status wait_until(unique_lock& lock, const chrono::time_point& abs_time); template bool wait_until(unique_lock& lock, const chrono::time_point& abs_time, Predicate pred); template cv_status wait_for(unique_lock& lock, const chrono::duration& rel_time); template bool wait_for(unique_lock& lock, const chrono::duration& rel_time, Predicate pred); using native_handle_type = @\impdefnc@; // see~\ref{thread.req.native} native_handle_type native_handle(); // see~\ref{thread.req.native} }; } \end{codeblock} \pnum The class \tcode{condition_variable} is a standard-layout class\iref{class.prop}. \indexlibraryctor{condition_variable}% \begin{itemdecl} condition_variable(); \end{itemdecl} \begin{itemdescr} \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{resource_unavailable_try_again} --- if some non-memory resource limitation prevents initialization. \end{itemize} \end{itemdescr} \indexlibrarydtor{condition_variable}% \begin{itemdecl} ~condition_variable(); \end{itemdecl} \begin{itemdescr} \pnum \expects There is no thread blocked on \tcode{*this}. \begin{note} That is, all threads have been notified; they can subsequently block on the lock specified in the wait. This relaxes the usual rules, which would have required all wait calls to happen before destruction. Only the notification to unblock the wait needs to happen before destruction. Undefined behavior ensues if a thread waits on \tcode{*this} once the destructor has been started, especially when the waiting threads are calling the wait functions in a loop or using the overloads of \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until} that take a predicate. \end{note} \end{itemdescr} \indexlibrarymember{notify_one}{condition_variable}% \begin{itemdecl} void notify_one() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If any threads are blocked waiting for \tcode{*this}, unblocks one of those threads. \end{itemdescr} \indexlibrarymember{notify_all}{condition_variable}% \begin{itemdecl} void notify_all() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks all threads that are blocked waiting for \tcode{*this}. \end{itemdescr} \indexlibrarymember{wait}{condition_variable}% \begin{itemdecl} void wait(unique_lock& lock); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread, and either \begin{itemize} \item no other thread is waiting on this \tcode{condition_variable} object or \item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until}) threads. \end{itemize} \pnum \indextext{block (execution)}% \effects \begin{itemize} \item Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. \item When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock), then returns. \item The function will unblock when signaled by a call to \tcode{notify_one()} or a call to \tcode{notify_all()}, or spuriously. \end{itemize} \pnum \ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread. \pnum \throws Nothing. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate()} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \indexlibrarymember{wait}{condition_variable}% \begin{itemdecl} template void wait(unique_lock& lock, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread, and either \begin{itemize} \item no other thread is waiting on this \tcode{condition_variable} object or \item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until}) threads. \end{itemize} \pnum \effects Equivalent to: \begin{codeblock} while (!pred()) wait(lock); \end{codeblock} \pnum \ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread. \pnum \throws Any exception thrown by \tcode{pred}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate()} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \indexlibrarymember{wait_until}{condition_variable}% \begin{itemdecl} template cv_status wait_until(unique_lock& lock, const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread, and either \begin{itemize} \item no other thread is waiting on this \tcode{condition_variable} object or \item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until}) threads. \end{itemize} \pnum \effects \begin{itemize} \item Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. \item When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock), then returns. \item The function will unblock when signaled by a call to \tcode{notify_one()}, a call to \tcode{notify_all()}, expiration of the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}, or spuriously. \item If the function exits via an exception, \tcode{lock.lock()} is called prior to exiting the function. \end{itemize} \pnum \ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread. \pnum \returns \tcode{cv_status::timeout} if the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} expired, otherwise \tcode{cv_status::no_timeout}. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate()} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \indexlibrarymember{wait_for}{condition_variable}% \begin{itemdecl} template cv_status wait_for(unique_lock& lock, const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread, and either \begin{itemize} \item no other thread is waiting on this \tcode{condition_variable} object or \item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until}) threads. \end{itemize} \pnum \effects Equivalent to: \begin{codeblock} return wait_until(lock, chrono::steady_clock::now() + rel_time); \end{codeblock} \pnum \ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread. \pnum \returns \tcode{cv_status::timeout} if the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} expired, otherwise \tcode{cv_status::no_timeout}. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \indexlibrarymember{wait_until}{condition_variable}% \begin{itemdecl} template bool wait_until(unique_lock& lock, const chrono::time_point& abs_time, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread, and either \begin{itemize} \item no other thread is waiting on this \tcode{condition_variable} object or \item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until}) threads. \end{itemize} \pnum \effects Equivalent to: \begin{codeblock} while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true; \end{codeblock} \pnum \ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread. \pnum \begin{note} The returned value indicates whether the predicate evaluated to \tcode{true} regardless of whether the timeout was triggered. \end{note} \pnum \throws Timeout-related exceptions\iref{thread.req.timing} or any exception thrown by \tcode{pred}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate()} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \indexlibrarymember{wait_for}{condition_variable}% \begin{itemdecl} template bool wait_for(unique_lock& lock, const chrono::duration& rel_time, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread, and either \begin{itemize} \item no other thread is waiting on this \tcode{condition_variable} object or \item \tcode{lock.mutex()} returns the same value for each of the \tcode{lock} arguments supplied by all concurrently waiting (via \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until}) threads. \end{itemize} \pnum \effects Equivalent to: \begin{codeblock} return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); \end{codeblock} \pnum \begin{note} There is no blocking if \tcode{pred()} is initially \tcode{true}, even if the timeout has already expired. \end{note} \pnum \ensures \tcode{lock.owns_lock()} is \tcode{true} and \tcode{lock.mutex()} is locked by the calling thread. \pnum \begin{note} The returned value indicates whether the predicate evaluates to \tcode{true} regardless of whether the timeout was triggered. \end{note} \pnum \throws Timeout-related exceptions\iref{thread.req.timing} or any exception thrown by \tcode{pred}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate()} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \rSec2[thread.condition.condvarany]{Class \tcode{condition_variable_any}} \rSec3[thread.condition.condvarany.general]{General} \pnum In this subclause \ref{thread.condition.condvarany}, template arguments for template parameters named \tcode{Lock} shall meet the \oldconcept{Basic\-Lockable} requirements\iref{thread.req.lockable.basic}. \begin{note} All of the standard mutex types meet this requirement. If a type other than one of the standard mutex types or a \tcode{unique_lock} wrapper for a standard mutex type is used with \tcode{condition_variable_any}, any necessary synchronization is assumed to be in place with respect to the predicate associated with the \tcode{condition_variable_any} instance. \end{note} \indexlibraryglobal{condition_variable_any}% \begin{codeblock} namespace std { class condition_variable_any { public: condition_variable_any(); ~condition_variable_any(); condition_variable_any(const condition_variable_any&) = delete; condition_variable_any& operator=(const condition_variable_any&) = delete; void notify_one() noexcept; void notify_all() noexcept; // \ref{thread.condvarany.wait}, noninterruptible waits template void wait(Lock& lock); template void wait(Lock& lock, Predicate pred); template cv_status wait_until(Lock& lock, const chrono::time_point& abs_time); template bool wait_until(Lock& lock, const chrono::time_point& abs_time, Predicate pred); template cv_status wait_for(Lock& lock, const chrono::duration& rel_time); template bool wait_for(Lock& lock, const chrono::duration& rel_time, Predicate pred); // \ref{thread.condvarany.intwait}, interruptible waits template bool wait(Lock& lock, stop_token stoken, Predicate pred); template bool wait_until(Lock& lock, stop_token stoken, const chrono::time_point& abs_time, Predicate pred); template bool wait_for(Lock& lock, stop_token stoken, const chrono::duration& rel_time, Predicate pred); }; } \end{codeblock} \indexlibraryctor{condition_variable_any}% \begin{itemdecl} condition_variable_any(); \end{itemdecl} \begin{itemdescr} \pnum \throws \tcode{bad_alloc} or \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors \begin{itemize} \item \tcode{resource_unavailable_try_again} --- if some non-memory resource limitation prevents initialization. \item \tcode{operation_not_permitted} --- if the thread does not have the privilege to perform the operation. \end{itemize} \end{itemdescr} \indexlibrarydtor{condition_variable_any}% \begin{itemdecl} ~condition_variable_any(); \end{itemdecl} \begin{itemdescr} \pnum \expects There is no thread blocked on \tcode{*this}. \begin{note} That is, all threads have been notified; they can subsequently block on the lock specified in the wait. This relaxes the usual rules, which would have required all wait calls to happen before destruction. Only the notification to unblock the wait needs to happen before destruction. Undefined behavior ensues if a thread waits on \tcode{*this} once the destructor has been started, especially when the waiting threads are calling the wait functions in a loop or using the overloads of \tcode{wait}, \tcode{wait_for}, or \tcode{wait_until} that take a predicate. \end{note} \end{itemdescr} \indexlibrarymember{notify_one}{condition_variable_any}% \begin{itemdecl} void notify_one() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If any threads are blocked waiting for \tcode{*this}, unblocks one of those threads. \end{itemdescr} \indexlibrarymember{notify_all}{condition_variable_any}% \begin{itemdecl} void notify_all() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Unblocks all threads that are blocked waiting for \tcode{*this}. \end{itemdescr} \rSec3[thread.condvarany.wait]{Noninterruptible waits} \indexlibrarymember{wait}{condition_variable_any}% \begin{itemdecl} template void wait(Lock& lock); \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects \begin{itemize} \item Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. \item When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock) and returns. \item The function will unblock when signaled by a call to \tcode{notify_one()}, a call to \tcode{notify_all()}, or spuriously. \end{itemize} \pnum \ensures \tcode{lock} is locked by the calling thread. \pnum \throws Nothing. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate()} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \indexlibrarymember{wait}{condition_variable_any}% \begin{itemdecl} template void wait(Lock& lock, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} while (!pred()) wait(lock); \end{codeblock} \end{itemdescr} \indexlibrarymember{wait_until}{condition_variable_any}% \begin{itemdecl} template cv_status wait_until(Lock& lock, const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum \effects \begin{itemize} \item \indextext{block (execution)}% Atomically calls \tcode{lock.unlock()} and blocks on \tcode{*this}. \item When unblocked, calls \tcode{lock.lock()} (possibly blocking on the lock) and returns. \item The function will unblock when signaled by a call to \tcode{notify_one()}, a call to \tcode{notify_all()}, expiration of the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time}, or spuriously. \item If the function exits via an exception, \tcode{lock.lock()} is called prior to exiting the function. \end{itemize} \pnum \ensures \tcode{lock} is locked by the calling thread. \pnum \returns \tcode{cv_status::timeout} if the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} expired, otherwise \tcode{cv_status::no_timeout}. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate()} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \indexlibrarymember{wait_for}{condition_variable_any}% \begin{itemdecl} template cv_status wait_for(Lock& lock, const chrono::duration& rel_time); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return wait_until(lock, chrono::steady_clock::now() + rel_time); \end{codeblock} \pnum \ensures \tcode{lock} is locked by the calling thread. \pnum \returns \tcode{cv_status::timeout} if the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} expired, otherwise \tcode{cv_status::no_timeout}. \pnum \throws Timeout-related exceptions\iref{thread.req.timing}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate} is invoked\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \indexlibrarymember{wait_until}{condition_variable_any}% \begin{itemdecl} template bool wait_until(Lock& lock, const chrono::time_point& abs_time, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true; \end{codeblock} \pnum \begin{note} There is no blocking if \tcode{pred()} is initially \tcode{true}, or if the timeout has already expired. \end{note} \pnum \begin{note} The returned value indicates whether the predicate evaluates to \tcode{true} regardless of whether the timeout was triggered. \end{note} \end{itemdescr} \indexlibrarymember{wait_for}{condition_variable_any}% \begin{itemdecl} template bool wait_for(Lock& lock, const chrono::duration& rel_time, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); \end{codeblock} \end{itemdescr} \rSec3[thread.condvarany.intwait]{Interruptible waits} \pnum The following wait functions will be notified when there is a stop request on the passed \tcode{stop_token}. In that case the functions return immediately, returning \tcode{false} if the predicate evaluates to \tcode{false}. \begin{itemdecl} template bool wait(Lock& lock, stop_token stoken, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \effects Registers for the duration of this call \tcode{*this} to get notified on a stop request on \tcode{stoken} during this call and then equivalent to: \begin{codeblock} while (!stoken.stop_requested()) { if (pred()) return true; wait(lock); } return pred(); \end{codeblock} \pnum \begin{note} The returned value indicates whether the predicate evaluated to \tcode{true} regardless of whether there was a stop request. \end{note} \pnum \ensures \tcode{lock} is locked by the calling thread. \pnum \throws Any exception thrown by \tcode{pred}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate} is called\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \begin{itemdecl} template bool wait_until(Lock& lock, stop_token stoken, const chrono::time_point& abs_time, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \effects Registers for the duration of this call \tcode{*this} to get notified on a stop request on \tcode{stoken} during this call and then equivalent to: \begin{codeblock} while (!stoken.stop_requested()) { if (pred()) return true; if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); } return pred(); \end{codeblock} \pnum \begin{note} There is no blocking if \tcode{pred()} is initially \tcode{true}, \tcode{stoken.stop_requested()} was already \tcode{true} or the timeout has already expired. \end{note} \pnum \begin{note} The returned value indicates whether the predicate evaluated to \tcode{true} regardless of whether the timeout was triggered or a stop request was made. \end{note} \pnum \ensures \tcode{lock} is locked by the calling thread. \pnum \throws Timeout-related exceptions \iref{thread.req.timing}, or any exception thrown by \tcode{pred}. \pnum \remarks If the function fails to meet the postcondition, \tcode{terminate} is called\iref{except.terminate}. \begin{note} This can happen if the re-locking of the mutex throws an exception. \end{note} \end{itemdescr} \begin{itemdecl} template bool wait_for(Lock& lock, stop_token stoken, const chrono::duration& rel_time, Predicate pred); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return wait_until(lock, std::move(stoken), chrono::steady_clock::now() + rel_time, std::move(pred)); \end{codeblock} \end{itemdescr} \rSec1[thread.sema]{Semaphore} \rSec2[thread.sema.general]{General} \pnum Semaphores are lightweight synchronization primitives used to constrain concurrent access to a shared resource. They are widely used to implement other synchronization primitives and, whenever both are applicable, can be more efficient than condition variables. \pnum A counting semaphore is a semaphore object that models a non-negative resource count. A binary semaphore is a semaphore object that has only two states. A binary semaphore should be more efficient than the default implementation of a counting semaphore with a unit resource count. \rSec2[semaphore.syn]{Header \tcode{} synopsis} \indexheader{semaphore}% \begin{codeblock} namespace std { // \ref{thread.sema.cnt}, class template \tcode{counting_semaphore} template class counting_semaphore; using binary_semaphore = counting_semaphore<1>; } \end{codeblock} \rSec2[thread.sema.cnt]{Class template \tcode{counting_semaphore}} \begin{codeblock} namespace std { template class counting_semaphore { public: static constexpr ptrdiff_t max() noexcept; constexpr explicit counting_semaphore(ptrdiff_t desired); ~counting_semaphore(); counting_semaphore(const counting_semaphore&) = delete; counting_semaphore& operator=(const counting_semaphore&) = delete; void release(ptrdiff_t update = 1); void acquire(); bool try_acquire() noexcept; template bool try_acquire_for(const chrono::duration& rel_time); template bool try_acquire_until(const chrono::time_point& abs_time); private: ptrdiff_t counter; // \expos }; } \end{codeblock} \pnum \indextext{block (execution)}% Class template \tcode{counting_semaphore} maintains an internal counter that is initialized when the semaphore is created. The counter is decremented when a thread acquires the semaphore, and is incremented when a thread releases the semaphore. If a thread tries to acquire the semaphore when the counter is zero, the thread will block until another thread increments the counter by releasing the semaphore. \pnum \tcode{least_max_value} shall be non-negative; otherwise the program is ill-formed. \pnum Concurrent invocations of the member functions of \tcode{counting_semaphore}, other than its destructor, do not introduce data races. \indexlibrarymember{max}{counting_semaphore}% \begin{itemdecl} static constexpr ptrdiff_t max() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns The maximum value of \tcode{counter}. This value is greater than or equal to \tcode{least_max_value}. \end{itemdescr} \indexlibraryctor{counting_semaphore}% \begin{itemdecl} constexpr explicit counting_semaphore(ptrdiff_t desired); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{desired >= 0} is \tcode{true}, and \tcode{desired <= max()} is \tcode{true}. \pnum \effects Initializes \tcode{counter} with \tcode{desired}. \pnum \throws Nothing. \end{itemdescr} \indexlibrarymember{release}{counting_semaphore}% \begin{itemdecl} void release(ptrdiff_t update = 1); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{update >= 0} is \tcode{true}, and \tcode{update <= max() - counter} is \tcode{true}. \pnum \effects Atomically execute \tcode{counter += update}. Then, unblocks any threads that are waiting for \tcode{counter} to be greater than zero. \pnum \sync Strongly happens before invocations of \tcode{try_acquire} that observe the result of the effects. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors Any of the error conditions allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} \indexlibrarymember{try_acquire}{counting_semaphore}% \begin{itemdecl} bool try_acquire() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Attempts to atomically decrement \tcode{counter} if it is positive, without blocking. If \tcode{counter} is not decremented, there is no effect and \tcode{try_acquire} immediately returns. An implementation may fail to decrement \tcode{counter} even if it is positive. \begin{note} This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange\iref{atomics}. \end{note} An implementation should ensure that \tcode{try_acquire} does not consistently return \tcode{false} in the absence of contending semaphore operations. \pnum \returns \tcode{true} if \tcode{counter} was decremented, otherwise \tcode{false}. \end{itemdescr} \indexlibrarymember{acquire}{counting_semaphore}% \begin{itemdecl} void acquire(); \end{itemdecl} \begin{itemdescr} \pnum \effects Repeatedly performs the following steps, in order: \begin{itemize} \item Evaluates \tcode{try_acquire()}. If the result is \tcode{true}, returns. \item \indextext{block (execution)}% Blocks on \tcode{*this} until \tcode{counter} is greater than zero. \end{itemize} \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors Any of the error conditions allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} \indexlibrarymember{try_acquire_for}{counting_semaphore}% \indexlibrarymember{try_acquire_until}{counting_semaphore}% \begin{itemdecl} template bool try_acquire_for(const chrono::duration& rel_time); template bool try_acquire_until(const chrono::time_point& abs_time); \end{itemdecl} \begin{itemdescr} \pnum \effects Repeatedly performs the following steps, in order: \begin{itemize} \item Evaluates \tcode{try_acquire()}. If the result is \tcode{true}, returns \tcode{true}. \item \indextext{block (execution)}% Blocks on \tcode{*this} until \tcode{counter} is greater than zero or until the timeout expires. If it is unblocked by the timeout expiring, returns \tcode{false}. \end{itemize} The timeout expires\iref{thread.req.timing} when the current time is after \tcode{abs_time} (for \tcode{try_acquire_until}) or when at least \tcode{rel_time} has passed from the start of the function (for \tcode{try_acquire_for}). \pnum \throws Timeout-related exceptions\iref{thread.req.timing}, or \tcode{system_error} when a non-timeout-related exception is required\iref{thread.req.exception}. \pnum \errors Any of the error conditions allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} \rSec1[thread.coord]{Coordination types} \rSec2[thread.coord.general]{General} \pnum Subclause \ref{thread.coord} describes various concepts related to thread coordination, and defines the coordination types \tcode{latch} and \tcode{barrier}. These types facilitate concurrent computation performed by a number of threads. \rSec2[thread.latch]{Latches} \rSec3[thread.latch.general]{General} \pnum A latch is a thread coordination mechanism that allows any number of threads to block until an expected number of threads arrive at the latch (via the \tcode{count_down} function). The expected count is set when the latch is created. An individual latch is a single-use object; once the expected count has been reached, the latch cannot be reused. \rSec3[latch.syn]{Header \tcode{} synopsis} \indexheader{latch}% \begin{codeblock} namespace std { class latch; } \end{codeblock} \rSec3[thread.latch.class]{Class \tcode{latch}} \begin{codeblock} namespace std { class latch { public: static constexpr ptrdiff_t max() noexcept; constexpr explicit latch(ptrdiff_t expected); ~latch(); latch(const latch&) = delete; latch& operator=(const latch&) = delete; void count_down(ptrdiff_t update = 1); bool try_wait() const noexcept; void wait() const; void arrive_and_wait(ptrdiff_t update = 1); private: ptrdiff_t counter; // \expos }; } \end{codeblock} \pnum A \tcode{latch} maintains an internal counter that is initialized when the latch is created. Threads can block on the latch object, waiting for counter to be decremented to zero. \pnum Concurrent invocations of the member functions of \tcode{latch}, other than its destructor, do not introduce data races. \indexlibrarymember{max}{latch}% \begin{itemdecl} static constexpr ptrdiff_t max() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns The maximum value of \tcode{counter} that the implementation supports. \end{itemdescr} \indexlibraryctor{latch}% \begin{itemdecl} constexpr explicit latch(ptrdiff_t expected); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{expected >= 0} is \tcode{true} and \tcode{expected <= max()} is \tcode{true}. \pnum \effects Initializes \tcode{counter} with \tcode{expected}. \pnum \throws Nothing. \end{itemdescr} \indexlibrarymember{count_down}{latch}% \begin{itemdecl} void count_down(ptrdiff_t update = 1); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{update >= 0} is \tcode{true}, and \tcode{update <= counter} is \tcode{true}. \pnum \effects Atomically decrements \tcode{counter} by \tcode{update}. If \tcode{counter} is equal to zero, unblocks all threads blocked on \tcode{*this}. \pnum \sync Strongly happens before the returns from all calls that are unblocked. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors Any of the error conditions allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} \indexlibrarymember{try_wait}{latch}% \begin{itemdecl} bool try_wait() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns With very low probability \tcode{false}. Otherwise \tcode{counter == 0}. \end{itemdescr} \indexlibrarymember{wait}{latch}% \begin{itemdecl} void wait() const; \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects If \tcode{counter} equals zero, returns immediately. Otherwise, blocks on \tcode{*this} until a call to \tcode{count_down} that decrements \tcode{counter} to zero. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors Any of the error conditions allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} \indexlibrarymember{arrive_and_wait}{latch}% \begin{itemdecl} void arrive_and_wait(ptrdiff_t update = 1); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} count_down(update); wait(); \end{codeblock} \end{itemdescr} \rSec2[thread.barrier]{Barriers} \rSec3[thread.barrier.general]{General} \pnum A barrier is a thread coordination mechanism whose lifetime consists of a sequence of barrier phases, where each phase allows at most an expected number of threads to block until the expected number of threads arrive at the barrier. \begin{note} A barrier is useful for managing repeated tasks that are handled by multiple threads. \end{note} \rSec3[barrier.syn]{Header \tcode{} synopsis} \indexheader{barrier}% \begin{codeblock} namespace std { template class barrier; } \end{codeblock} \rSec3[thread.barrier.class]{Class template \tcode{barrier}} \begin{codeblock} namespace std { template class barrier { public: using arrival_token = @\seebelow@; static constexpr ptrdiff_t max() noexcept; constexpr explicit barrier(ptrdiff_t expected, CompletionFunction f = CompletionFunction()); ~barrier(); barrier(const barrier&) = delete; barrier& operator=(const barrier&) = delete; [[nodiscard]] arrival_token arrive(ptrdiff_t update = 1); void wait(arrival_token&& arrival) const; void arrive_and_wait(); void arrive_and_drop(); private: CompletionFunction completion; // \expos }; } \end{codeblock} \pnum Each \defn{barrier phase} consists of the following steps: \begin{itemize} \item The expected count is decremented by each call to \tcode{arrive} or \tcode{arrive_and_drop}. \item Exactly once after the expected count reaches zero, a thread executes the completion step during its call to \tcode{arrive}, \tcode{arrive_and_drop}, or \tcode{wait}, except that it is \impldef{barrier phrase completion without \tcode{wait}} whether the step executes if no thread calls \tcode{wait}. \item When the completion step finishes, the expected count is reset to what was specified by the \tcode{expected} argument to the constructor, possibly adjusted by calls to \tcode{arrive_and_drop}, and the next phase starts. \end{itemize} \indextext{phase synchronization point|see{barrier, phase synchronization point}}% \pnum \indextext{block (execution)}% Each phase defines a \defnx{phase synchronization point}{barrier!phase synchronization point}. Threads that arrive at the barrier during the phase can block on the phase synchronization point by calling \tcode{wait}, and will remain blocked until the phase completion step is run. \pnum The \defn{phase completion step} that is executed at the end of each phase has the following effects: \begin{itemize} \item Invokes the completion function, equivalent to \tcode{completion()}. \item Unblocks all threads that are blocked on the phase synchronization point. \end{itemize} The end of the completion step strongly happens before the returns from all calls that were unblocked by the completion step. For specializations that do not have the default value of the \tcode{CompletionFunction} template parameter, the behavior is undefined if any of the barrier object's member functions other than \tcode{wait} are called while the completion step is in progress. \pnum Concurrent invocations of the member functions of \tcode{barrier}, other than its destructor, do not introduce data races. The member functions \tcode{arrive} and \tcode{arrive_and_drop} execute atomically. \pnum \tcode{CompletionFunction} shall meet the \oldconcept{MoveConstructible} (\tref{cpp17.moveconstructible}) and \oldconcept{Destructible} (\tref{cpp17.destructible}) requirements. \tcode{is_nothrow_invocable_v} shall be \tcode{true}. \pnum The default value of the \tcode{CompletionFunction} template parameter is an unspecified type, such that, in addition to satisfying the requirements of \tcode{CompletionFunction}, it meets the \oldconcept{DefaultConstructible} requirements (\tref{cpp17.defaultconstructible}) and \tcode{completion()} has no effects. \pnum \tcode{barrier::arrival_token} is an unspecified type, such that it meets the \oldconcept{MoveConstructible} (\tref{cpp17.moveconstructible}), \oldconcept{MoveAssignable} (\tref{cpp17.moveassignable}), and \oldconcept{Destructible} (\tref{cpp17.destructible}) requirements. \indexlibrarymember{max}{barrier}% \begin{itemdecl} static constexpr ptrdiff_t max() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns The maximum expected count that the implementation supports. \end{itemdescr} \indexlibraryctor{barrier} \begin{itemdecl} constexpr explicit barrier(ptrdiff_t expected, CompletionFunction f = CompletionFunction()); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{expected >= 0} is \tcode{true} and \tcode{expected <= max()} is \tcode{true}. \pnum \effects Sets both the initial expected count for each barrier phase and the current expected count for the first phase to \tcode{expected}. Initializes \tcode{completion} with \tcode{std::move(f)}. Starts the first phase. \begin{note} If \tcode{expected} is 0 this object can only be destroyed. \end{note} \pnum \throws Any exception thrown by \tcode{CompletionFunction}'s move constructor. \end{itemdescr} \indexlibrarymember{arrive}{barrier}% \begin{itemdecl} [[nodiscard]] arrival_token arrive(ptrdiff_t update = 1); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{update > 0} is \tcode{true}, and \tcode{update} is less than or equal to the expected count for the current barrier phase. \pnum \effects Constructs an object of type \tcode{arrival_token} that is associated with the phase synchronization point for the current phase. Then, decrements the expected count by \tcode{update}. \pnum \sync The call to \tcode{arrive} strongly happens before the start of the phase completion step for the current phase. \pnum \returns The constructed \tcode{arrival_token} object. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors Any of the error conditions allowed for mutex types\iref{thread.mutex.requirements.mutex}. \pnum \begin{note} This call can cause the completion step for the current phase to start. \end{note} \end{itemdescr} \indexlibrarymember{wait}{barrier}% \begin{itemdecl} void wait(arrival_token&& arrival) const; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{arrival} is associated with the phase synchronization point for the current phase or the immediately preceding phase of the same barrier object. \pnum \indextext{block (execution)}% \effects Blocks at the synchronization point associated with \tcode{std::move(arrival)} until the phase completion step of the synchronization point's phase is run. \begin{note} If \tcode{arrival} is associated with the synchronization point for a previous phase, the call returns immediately. \end{note} \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors Any of the error conditions allowed for mutex types\iref{thread.mutex.requirements.mutex}. \end{itemdescr} \indexlibrarymember{arrive_and_wait}{barrier}% \begin{itemdecl} void arrive_and_wait(); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{wait(arrive())}. \end{itemdescr} \indexlibrarymember{arrive_and_drop}{barrier}% \begin{itemdecl} void arrive_and_drop(); \end{itemdecl} \begin{itemdescr} \pnum \expects The expected count for the current barrier phase is greater than zero. \pnum \effects Decrements the initial expected count for all subsequent phases by one. Then decrements the expected count for the current phase by one. \pnum \sync The call to \tcode{arrive_and_drop} strongly happens before the start of the phase completion step for the current phase. \pnum \throws \tcode{system_error} when an exception is required\iref{thread.req.exception}. \pnum \errors Any of the error conditions allowed for mutex types\iref{thread.mutex.requirements.mutex}. \pnum \begin{note} This call can cause the completion step for the current phase to start. \end{note} \end{itemdescr} \rSec1[futures]{Futures} \rSec2[futures.overview]{Overview} \pnum \ref{futures} describes components that a \Cpp{} program can use to retrieve in one thread the result (value or exception) from a function that has run in the same thread or another thread. \begin{note} These components are not restricted to multi-threaded programs but can be useful in single-threaded programs as well. \end{note} \rSec2[future.syn]{Header \tcode{} synopsis} \indexheader{future}% \indexlibraryglobal{future_errc}% \begin{codeblock} namespace std { enum class future_errc { broken_promise = @\impdefx{value of \tcode{future_errc::broken_promise}}@, future_already_retrieved = @\impdefx{value of \tcode{future_errc::future_already_retrieved}}@, promise_already_satisfied = @\impdefx{value of \tcode{future_errc::promise_already_satisfied}}@, no_state = @\impdefx{value of \tcode{future_errc::no_state}}@ }; enum class launch : @\unspec{}@ { async = @\unspec{}@, deferred = @\unspec{}@, @\impdefx{last enumerator of \tcode{launch}}@ }; enum class future_status { ready, timeout, deferred }; // \ref{futures.errors}, error handling template<> struct is_error_code_enum : public true_type { }; error_code make_error_code(future_errc e) noexcept; error_condition make_error_condition(future_errc e) noexcept; const error_category& future_category() noexcept; // \ref{futures.future.error}, class \tcode{future_error} class future_error; // \ref{futures.promise}, class template \tcode{promise} template class promise; template class promise; template<> class promise; template void swap(promise& x, promise& y) noexcept; template struct uses_allocator, Alloc>; // \ref{futures.unique.future}, class template \tcode{future} template class future; template class future; template<> class future; // \ref{futures.shared.future}, class template \tcode{shared_future} template class shared_future; template class shared_future; template<> class shared_future; // \ref{futures.task}, class template \tcode{packaged_task} template class packaged_task; // \notdef template class packaged_task; template void swap(packaged_task&, packaged_task&) noexcept; // \ref{futures.async}, function template \tcode{async} template [[nodiscard]] future, decay_t...>> async(F&& f, Args&&... args); template [[nodiscard]] future, decay_t...>> async(launch policy, F&& f, Args&&... args); } \end{codeblock} \pnum The \keyword{enum} type \tcode{launch} is a bitmask type\iref{bitmask.types} with elements \tcode{launch::async} and \tcode{launch::deferred}. \begin{note} Implementations can provide bitmasks to specify restrictions on task interaction by functions launched by \tcode{async()} applicable to a corresponding subset of available launch policies. Implementations can extend the behavior of the first overload of \tcode{async()} by adding their extensions to the launch policy under the ``as if'' rule. \end{note} \pnum The enum values of \tcode{future_errc} are distinct and not zero. \rSec2[futures.errors]{Error handling} \indexlibraryglobal{future_category}% \begin{itemdecl} const error_category& future_category() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A reference to an object of a type derived from class \tcode{error_category}. \pnum The object's \tcode{default_error_condition} and \tcode{equivalent} virtual functions shall behave as specified for the class \tcode{error_category}. The object's \tcode{name} virtual function returns a pointer to the string \tcode{"future"}. \end{itemdescr} \indexlibrarymember{make_error_code}{future_errc}% \begin{itemdecl} error_code make_error_code(future_errc e) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{error_code(static_cast(e), future_category())}. \end{itemdescr} \indexlibrarymember{make_error_condition}{future_errc}% \begin{itemdecl} error_condition make_error_condition(future_errc e) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{error_condition(static_cast(e), future_category())}. \end{itemdescr} \rSec2[futures.future.error]{Class \tcode{future_error}} \indexlibraryglobal{future_error}% \begin{codeblock} namespace std { class future_error : public logic_error { public: explicit future_error(future_errc e); const error_code& code() const noexcept; const char* what() const noexcept; private: error_code ec_; // \expos }; } \end{codeblock} \indexlibraryctor{future_error}% \begin{itemdecl} explicit future_error(future_errc e); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{ec_} with \tcode{make_error_code(e)}. \end{itemdescr} \indexlibrarymember{code}{future_error}% \begin{itemdecl} const error_code& code() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{ec_}. \end{itemdescr} \indexlibrarymember{what}{future_error}% \begin{itemdecl} const char* what() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns An \ntbs{} incorporating \tcode{code().message()}. \end{itemdescr} \rSec2[futures.state]{Shared state} \pnum Many of the classes introduced in subclause~\ref{futures} use some state to communicate results. This \indextext{shared state|see{future, shared state}} \defnx{shared state}{future!shared state} consists of some state information and some (possibly not yet evaluated) \term{result}, which can be a (possibly void) value or an exception. \begin{note} Futures, promises, and tasks defined in this Clause reference such shared state. \end{note} \pnum \begin{note} The result can be any kind of object including a function to compute that result, as used by \tcode{async} when \tcode{policy} is \tcode{launch::deferred}. \end{note} \pnum An \defn{asynchronous return object} is an object that reads results from a shared state. A \defnadj{waiting}{function} of an asynchronous return object is one that potentially blocks to wait for the shared state to be made ready. If a waiting function can return before the state is made ready because of a timeout\iref{thread.req.lockable}, then it is a \term{timed waiting function}, otherwise it is a \term{non-timed waiting function}. \pnum An \defn{asynchronous provider} is an object that provides a result to a shared state. The result of a shared state is set by respective functions on the asynchronous provider. \begin{note} Such as promises or tasks. \end{note} The means of setting the result of a shared state is specified in the description of those classes and functions that create such a state object. \pnum When an asynchronous return object or an asynchronous provider is said to release its shared state, it means: \begin{itemize} \item if the return object or provider holds the last reference to its shared state, the shared state is destroyed; and \item the return object or provider gives up its reference to its shared state; and \item these actions will not block for the shared state to become ready, except that it may block if all of the following are true: the shared state was created by a call to \tcode{std::async}, the shared state is not yet ready, and this was the last reference to the shared state. \end{itemize} \pnum When an asynchronous provider is said to make its shared state ready, it means: \begin{itemize} \item first, the provider marks its shared state as ready; and \item second, the provider unblocks any execution agents waiting for its shared state to become ready. \end{itemize} \pnum When an asynchronous provider is said to abandon its shared state, it means: \begin{itemize} \item first, if that state is not ready, the provider \begin{itemize} \item stores an exception object of type \tcode{future_error} with an error condition of \tcode{broken_promise} within its shared state; and then \item makes its shared state ready; \end{itemize} \item second, the provider releases its shared state. \end{itemize} \pnum A shared state is \defn{ready} only if it holds a value or an exception ready for retrieval. Waiting for a shared state to become ready may invoke code to compute the result on the waiting thread if so specified in the description of the class or function that creates the state object. \pnum Calls to functions that successfully set the stored result of a shared state synchronize with\iref{intro.multithread} calls to functions successfully detecting the ready state resulting from that setting. The storage of the result (whether normal or exceptional) into the shared state synchronizes with\iref{intro.multithread} the successful return from a call to a waiting function on the shared state. \pnum Some functions (e.g., \tcode{promise::set_value_at_thread_exit}) delay making the shared state ready until the calling thread exits. The destruction of each of that thread's objects with thread storage duration\iref{basic.stc.thread} is sequenced before making that shared state ready. \pnum Access to the result of the same shared state may conflict\iref{intro.multithread}. \begin{note} This explicitly specifies that the result of the shared state is visible in the objects that reference this state in the sense of data race avoidance\iref{res.on.data.races}. For example, concurrent accesses through references returned by \tcode{shared_future::get()}\iref{futures.shared.future} must either use read-only operations or provide additional synchronization. \end{note} \rSec2[futures.promise]{Class template \tcode{promise}} \indexlibraryglobal{promise}% \begin{codeblock} namespace std { template class promise { public: promise(); template promise(allocator_arg_t, const Allocator& a); promise(promise&& rhs) noexcept; promise(const promise&) = delete; ~promise(); // assignment promise& operator=(promise&& rhs) noexcept; promise& operator=(const promise&) = delete; void swap(promise& other) noexcept; // retrieving the result future get_future(); // setting the result void set_value(@\seebelow@); void set_exception(exception_ptr p); // setting the result with deferred notification void set_value_at_thread_exit(@\seebelow@); void set_exception_at_thread_exit(exception_ptr p); }; template struct uses_allocator, Alloc>; } \end{codeblock} \pnum For the primary template, \tcode{R} shall be an object type that meets the \oldconcept{Destructible} requirements. \pnum The implementation provides the template \tcode{promise} and two specializations, \tcode{promise} and \tcode{promise<\brk{}void>}. These differ only in the argument type of the member functions \tcode{set_value} and \tcode{set_value_at_thread_exit}, as set out in their descriptions, below. \pnum The \tcode{set_value}, \tcode{set_exception}, \tcode{set_value_at_thread_exit}, and \tcode{set_exception_at_thread_exit} member functions behave as though they acquire a single mutex associated with the promise object while updating the promise object. \indexlibrarymember{uses_allocator}{promise}% \begin{itemdecl} template struct uses_allocator, Alloc> : true_type { }; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{Alloc} meets the \oldconcept{Allocator} requirements\iref{allocator.requirements.general}. \end{itemdescr} \indexlibraryctor{promise}% \begin{itemdecl} promise(); template promise(allocator_arg_t, const Allocator& a); \end{itemdecl} \begin{itemdescr} \pnum \effects Creates a shared state. The second constructor uses the allocator \tcode{a} to allocate memory for the shared state. \end{itemdescr} \indexlibraryctor{promise}% \begin{itemdecl} promise(promise&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Transfers ownership of the shared state of \tcode{rhs} (if any) to the newly-constructed object. \pnum \ensures \tcode{rhs} has no shared state. \end{itemdescr} \indexlibrarydtor{promise}% \begin{itemdecl} ~promise(); \end{itemdecl} \begin{itemdescr} \pnum \effects Abandons any shared state\iref{futures.state}. \end{itemdescr} \indexlibrarymember{operator=}{promise}% \begin{itemdecl} promise& operator=(promise&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Abandons any shared state\iref{futures.state} and then as if \tcode{promise(std::move(rhs)).swap(*this)}. \pnum \returns \tcode{*this}. \end{itemdescr} \indexlibrarymember{swap}{promise}% \begin{itemdecl} void swap(promise& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Exchanges the shared state of \tcode{*this} and \tcode{other}. \pnum \ensures \tcode{*this} has the shared state (if any) that \tcode{other} had prior to the call to \tcode{swap}. \tcode{other} has the shared state (if any) that \tcode{*this} had prior to the call to \tcode{swap}. \end{itemdescr} \indexlibrarymember{get_future}{promise}% \begin{itemdecl} future get_future(); \end{itemdecl} \begin{itemdescr} \pnum \sync Calls to this function do not introduce data races~\iref{intro.multithread} with calls to \tcode{set_value}, \tcode{set_exception}, \tcode{set_value_at_thread_exit}, or \tcode{set_exception_at_thread_exit}. \begin{note} Such calls need not synchronize with each other. \end{note} \pnum \returns A \tcode{future} object with the same shared state as \tcode{*this}. \pnum \throws \tcode{future_error} if \tcode{*this} has no shared state or if \tcode{get_future} has already been called on a \tcode{promise} with the same shared state as \tcode{*this}. \pnum \errors \begin{itemize} \item \tcode{future_already_retrieved} if \tcode{get_future} has already been called on a \tcode{promise} with the same shared state as \tcode{*this}. \item \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \indexlibrarymember{set_value}{promise}% \begin{itemdecl} void promise::set_value(const R& r); void promise::set_value(R&& r); void promise::set_value(R& r); void promise::set_value(); \end{itemdecl} \begin{itemdescr} \pnum \effects Atomically stores the value \tcode{r} in the shared state and makes that state ready\iref{futures.state}. \pnum \throws \begin{itemize} \item \tcode{future_error} if its shared state already has a stored value or exception, or \item for the first version, any exception thrown by the constructor selected to copy an object of \tcode{R}, or \item for the second version, any exception thrown by the constructor selected to move an object of \tcode{R}. \end{itemize} \pnum \errors \begin{itemize} \item \tcode{promise_already_satisfied} if its shared state already has a stored value or exception. \item \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \indexlibrarymember{set_exception}{promise}% \begin{itemdecl} void set_exception(exception_ptr p); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{p} is not null. \pnum \effects Atomically stores the exception pointer \tcode{p} in the shared state and makes that state ready\iref{futures.state}. \pnum \throws \tcode{future_error} if its shared state already has a stored value or exception. \pnum \errors \begin{itemize} \item \tcode{promise_already_satisfied} if its shared state already has a stored value or exception. \item \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \indexlibrarymember{set_value_at_thread_exit}{promise}% \begin{itemdecl} void promise::set_value_at_thread_exit(const R& r); void promise::set_value_at_thread_exit(R&& r); void promise::set_value_at_thread_exit(R& r); void promise::set_value_at_thread_exit(); \end{itemdecl} \begin{itemdescr} \pnum \effects Stores the value \tcode{r} in the shared state without making that state ready immediately. Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. \pnum \throws \begin{itemize} \item \tcode{future_error} if its shared state already has a stored value or exception, or \item for the first version, any exception thrown by the constructor selected to copy an object of \tcode{R}, or \item for the second version, any exception thrown by the constructor selected to move an object of \tcode{R}. \end{itemize} \pnum \errors \begin{itemize} \item \tcode{promise_already_satisfied} if its shared state already has a stored value or exception. \item \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \indexlibrarymember{set_exception_at_thread_exit}{promise}% \begin{itemdecl} void set_exception_at_thread_exit(exception_ptr p); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{p} is not null. \pnum \effects Stores the exception pointer \tcode{p} in the shared state without making that state ready immediately. Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. \pnum \throws \tcode{future_error} if an error condition occurs. \pnum \errors \begin{itemize} \item \tcode{promise_already_satisfied} if its shared state already has a stored value or exception. \item \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \indexlibrarymember{swap}{promise}% \begin{itemdecl} template void swap(promise& x, promise& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{x.swap(y)}. \end{itemdescr} \rSec2[futures.unique.future]{Class template \tcode{future}} \pnum The class template \tcode{future} defines a type for asynchronous return objects which do not share their shared state with other asynchronous return objects. A default-constructed \tcode{future} object has no shared state. A \tcode{future} object with shared state can be created by functions on asynchronous providers\iref{futures.state} or by the move constructor and shares its shared state with the original asynchronous provider. The result (value or exception) of a \tcode{future} object can be set by calling a respective function on an object that shares the same shared state. \pnum \begin{note} Member functions of \tcode{future} do not synchronize with themselves or with member functions of \tcode{shared_future}. \end{note} \pnum The effect of calling any member function other than the destructor, the move-assignment operator, \tcode{share}, or \tcode{valid} on a \tcode{future} object for which \tcode{valid() == false} is undefined. \begin{note} It is valid to move from a future object for which \tcode{valid() == false}. \end{note} \recommended Implementations should detect this case and throw an object of type \tcode{future_error} with an error condition of \tcode{future_errc::no_state}. \indexlibraryglobal{future}% \begin{codeblock} namespace std { template class future { public: future() noexcept; future(future&&) noexcept; future(const future&) = delete; ~future(); future& operator=(const future&) = delete; future& operator=(future&&) noexcept; shared_future share() noexcept; // retrieving the value @\seebelow@ get(); // functions to check state bool valid() const noexcept; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; } \end{codeblock} \pnum For the primary template, \tcode{R} shall be an object type that meets the \oldconcept{Destructible} requirements. \pnum The implementation provides the template \tcode{future} and two specializations, \tcode{future} and \tcode{future<\brk{}void>}. These differ only in the return type and return value of the member function \tcode{get}, as set out in its description, below. \indexlibraryctor{future}% \begin{itemdecl} future() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects The object does not refer to a shared state. \pnum \ensures \tcode{valid() == false}. \end{itemdescr} \indexlibraryctor{future}% \begin{itemdecl} future(future&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Move constructs a \tcode{future} object that refers to the shared state that was originally referred to by \tcode{rhs} (if any). \pnum \ensures \begin{itemize} \item \tcode{valid()} returns the same value as \tcode{rhs.valid()} prior to the constructor invocation. \item \tcode{rhs.valid() == false}. \end{itemize} \end{itemdescr} \indexlibraryctor{future}% \begin{itemdecl} ~future(); \end{itemdecl} \begin{itemdescr} \pnum \effects \begin{itemize} \item Releases any shared state\iref{futures.state}; \item destroys \tcode{*this}. \end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{future}% \begin{itemdecl} future& operator=(future&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{addressof(rhs) == this} is \tcode{true}, there are no effects. Otherwise: \begin{itemize} \item Releases any shared state\iref{futures.state}. \item move assigns the contents of \tcode{rhs} to \tcode{*this}. \end{itemize} \pnum \ensures \begin{itemize} \item \tcode{valid()} returns the same value as \tcode{rhs.valid()} prior to the assignment. \item If \tcode{addressof(rhs) == this} is \tcode{false}, \tcode{rhs.valid() == false}. \end{itemize} \end{itemdescr} \indexlibrarymember{share}{future}% \begin{itemdecl} shared_future share() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{valid() == false}. \pnum \returns \tcode{shared_future(std::move(*this))}. \end{itemdescr} \indexlibrarymember{get}{future}% \begin{itemdecl} R future::get(); R& future::get(); void future::get(); \end{itemdecl} \begin{itemdescr} \pnum \begin{note} As described above, the template and its two required specializations differ only in the return type and return value of the member function \tcode{get}. \end{note} \pnum \effects \begin{itemize} \item \tcode{wait()}{s} until the shared state is ready, then retrieves the value stored in the shared state; \item releases any shared state\iref{futures.state}. \end{itemize} \pnum \ensures \tcode{valid() == false}. \pnum \returns \begin{itemize} \item \tcode{future::get()} returns the value \tcode{v} stored in the object's shared state as \tcode{std::move(v)}. \item \tcode{future::get()} returns the reference stored as value in the object's shared state. \item \tcode{future::get()} returns nothing. \end{itemize} \pnum \throws The stored exception, if an exception was stored in the shared state. \end{itemdescr} \indexlibrarymember{valid}{future}% \begin{itemdecl} bool valid() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} only if \tcode{*this} refers to a shared state. \end{itemdescr} \indexlibrarymember{wait}{future}% \begin{itemdecl} void wait() const; \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects Blocks until the shared state is ready. \end{itemdescr} \indexlibrarymember{wait_for}{future}% \begin{itemdecl} template future_status wait_for(const chrono::duration& rel_time) const; \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects None if the shared state contains a deferred function\iref{futures.async}, otherwise blocks until the shared state is ready or until the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} has expired. \pnum \returns \begin{itemize} \item \tcode{future_status::deferred} if the shared state contains a deferred function. \item \tcode{future_status::ready} if the shared state is ready. \item \tcode{future_status::timeout} if the function is returning because the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} has expired. \end{itemize} \pnum \throws timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \indexlibrarymember{wait_until}{future}% \begin{itemdecl} template future_status wait_until(const chrono::time_point& abs_time) const; \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects None if the shared state contains a deferred function\iref{futures.async}, otherwise blocks until the shared state is ready or until the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} has expired. \pnum \returns \begin{itemize} \item \tcode{future_status::deferred} if the shared state contains a deferred function. \item \tcode{future_status::ready} if the shared state is ready. \item \tcode{future_status::timeout} if the function is returning because the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} has expired. \end{itemize} \pnum \throws timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \rSec2[futures.shared.future]{Class template \tcode{shared_future}} \pnum The class template \tcode{shared_future} defines a type for asynchronous return objects which may share their shared state with other asynchronous return objects. A default-constructed \tcode{shared_future} object has no shared state. A \tcode{shared_future} object with shared state can be created by conversion from a \tcode{future} object and shares its shared state with the original asynchronous provider\iref{futures.state} of the shared state. The result (value or exception) of a \tcode{shared_future} object can be set by calling a respective function on an object that shares the same shared state. \pnum \begin{note} Member functions of \tcode{shared_future} do not synchronize with themselves, but they synchronize with the shared state. \end{note} \pnum The effect of calling any member function other than the destructor, the move-assignment operator, the copy-assignment operator, or \tcode{valid()} on a \tcode{shared_future} object for which \tcode{valid() == false} is undefined. \begin{note} It is valid to copy or move from a \tcode{shared_future} object for which \tcode{valid()} is \tcode{false}. \end{note} \recommended Implementations should detect this case and throw an object of type \tcode{future_error} with an error condition of \tcode{future_errc::no_state}. \indexlibraryglobal{shared_future}% \begin{codeblock} namespace std { template class shared_future { public: shared_future() noexcept; shared_future(const shared_future& rhs) noexcept; shared_future(future&&) noexcept; shared_future(shared_future&& rhs) noexcept; ~shared_future(); shared_future& operator=(const shared_future& rhs) noexcept; shared_future& operator=(shared_future&& rhs) noexcept; // retrieving the value @\seebelow@ get() const; // functions to check state bool valid() const noexcept; void wait() const; template future_status wait_for(const chrono::duration& rel_time) const; template future_status wait_until(const chrono::time_point& abs_time) const; }; } \end{codeblock} \pnum For the primary template, \tcode{R} shall be an object type that meets the \oldconcept{Destructible} requirements. \pnum The implementation provides the template \tcode{shared_future} and two specializations, \tcode{shared_future} and \tcode{shared_future}. These differ only in the return type and return value of the member function \tcode{get}, as set out in its description, below. \indexlibraryctor{shared_future}% \begin{itemdecl} shared_future() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects The object does not refer to a shared state. \pnum \ensures \tcode{valid() == false}. \end{itemdescr} \indexlibraryctor{shared_future}% \begin{itemdecl} shared_future(const shared_future& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects The object refers to the same shared state as \tcode{rhs} (if any). \pnum \ensures \tcode{valid()} returns the same value as \tcode{rhs.valid()}. \end{itemdescr} \indexlibraryctor{shared_future}% \begin{itemdecl} shared_future(future&& rhs) noexcept; shared_future(shared_future&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Move constructs a \tcode{shared_future} object that refers to the shared state that was originally referred to by \tcode{rhs} (if any). \pnum \ensures \begin{itemize} \item \tcode{valid()} returns the same value as \tcode{rhs.valid()} returned prior to the constructor invocation. \item \tcode{rhs.valid() == false}. \end{itemize} \end{itemdescr} \indexlibrarydtor{shared_future}% \begin{itemdecl} ~shared_future(); \end{itemdecl} \begin{itemdescr} \pnum \effects \begin{itemize} \item Releases any shared state\iref{futures.state}; \item destroys \tcode{*this}. \end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{shared_future}% \begin{itemdecl} shared_future& operator=(shared_future&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{addressof(rhs) == this} is \tcode{true}, there are no effects. Otherwise: \begin{itemize} \item Releases any shared state\iref{futures.state}; \item move assigns the contents of \tcode{rhs} to \tcode{*this}. \end{itemize} \pnum \ensures \begin{itemize} \item \tcode{valid()} returns the same value as \tcode{rhs.valid()} returned prior to the assignment. \item If \tcode{addressof(rhs) == this} is \tcode{false}, \tcode{rhs.valid() == false}. \end{itemize} \end{itemdescr} \indexlibrarymember{operator=}{shared_future}% \begin{itemdecl} shared_future& operator=(const shared_future& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{addressof(rhs) == this} is \tcode{true}, there are no effects. Otherwise: \begin{itemize} \item Releases any shared state\iref{futures.state}; \item assigns the contents of \tcode{rhs} to \tcode{*this}. \begin{note} As a result, \tcode{*this} refers to the same shared state as \tcode{rhs} (if any). \end{note} \end{itemize} \pnum \ensures \tcode{valid() == rhs.valid()}. \end{itemdescr} \indexlibrarymember{get}{shared_future}% \begin{itemdecl} const R& shared_future::get() const; R& shared_future::get() const; void shared_future::get() const; \end{itemdecl} \begin{itemdescr} \pnum \begin{note} As described above, the template and its two required specializations differ only in the return type and return value of the member function \tcode{get}. \end{note} \pnum \begin{note} Access to a value object stored in the shared state is unsynchronized, so operations on \tcode{R} might introduce a data race\iref{intro.multithread}. \end{note} \pnum \effects \tcode{wait()}{s} until the shared state is ready, then retrieves the value stored in the shared state. \pnum \returns \begin{itemize} \item \tcode{shared_future::get()} returns a const reference to the value stored in the object's shared state. \begin{note} Access through that reference after the shared state has been destroyed produces undefined behavior; this can be avoided by not storing the reference in any storage with a greater lifetime than the \tcode{shared_future} object that returned the reference. \end{note} \item \tcode{shared_future::get()} returns the reference stored as value in the object's shared state. \item \tcode{shared_future::get()} returns nothing. \end{itemize} \pnum \throws The stored exception, if an exception was stored in the shared state. \end{itemdescr} \indexlibrarymember{valid}{shared_future}% \begin{itemdecl} bool valid() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} only if \tcode{*this} refers to a shared state. \end{itemdescr} \indexlibrarymember{wait}{shared_future}% \begin{itemdecl} void wait() const; \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects Blocks until the shared state is ready. \end{itemdescr} \indexlibrarymember{wait_for}{shared_future}% \begin{itemdecl} template future_status wait_for(const chrono::duration& rel_time) const; \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects None if the shared state contains a deferred function\iref{futures.async}, otherwise blocks until the shared state is ready or until the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} has expired. \pnum \returns \begin{itemize} \item \tcode{future_status::deferred} if the shared state contains a deferred function. \item \tcode{future_status::ready} if the shared state is ready. \item \tcode{future_status::timeout} if the function is returning because the relative timeout\iref{thread.req.timing} specified by \tcode{rel_time} has expired. \end{itemize} \pnum \throws timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \indexlibrarymember{wait_until}{shared_future}% \begin{itemdecl} template future_status wait_until(const chrono::time_point& abs_time) const; \end{itemdecl} \begin{itemdescr} \pnum \indextext{block (execution)}% \effects None if the shared state contains a deferred function\iref{futures.async}, otherwise blocks until the shared state is ready or until the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} has expired. \pnum \returns \begin{itemize} \item \tcode{future_status::deferred} if the shared state contains a deferred function. \item \tcode{future_status::ready} if the shared state is ready. \item \tcode{future_status::timeout} if the function is returning because the absolute timeout\iref{thread.req.timing} specified by \tcode{abs_time} has expired. \end{itemize} \pnum \throws timeout-related exceptions\iref{thread.req.timing}. \end{itemdescr} \rSec2[futures.async]{Function template \tcode{async}} \pnum The function template \tcode{async} provides a mechanism to launch a function potentially in a new thread and provides the result of the function in a \tcode{future} object with which it shares a shared state. \indexlibraryglobal{async}% \begin{itemdecl} template [[nodiscard]] future, decay_t...>> async(F&& f, Args&&... args); template [[nodiscard]] future, decay_t...>> async(launch policy, F&& f, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \mandates The following are all \tcode{true}: \begin{itemize} \item \tcode{is_constructible_v, F>}, \item \tcode{(is_constructible_v, Args> \&\& ...)}, and \item \tcode{is_invocable_v, decay_t...>}. \end{itemize} \pnum \effects The first function behaves the same as a call to the second function with a \tcode{policy} argument of \tcode{launch::async | launch::deferred} and the same arguments for \tcode{F} and \tcode{Args}. The second function creates a shared state that is associated with the returned \tcode{future} object. The further behavior of the second function depends on the \tcode{policy} argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies): \begin{itemize} \item If \tcode{launch::async} is set in \tcode{policy}, calls \tcode{invoke(auto(std::forward(f)), auto(std::for\-ward(args))...)}\iref{func.invoke,thread.thread.constr} as if in a new thread of execution represented by a \tcode{thread} object with the values produced by \tcode{auto} being materialized\iref{conv.rval} in the thread that called \tcode{async}. Any return value is stored as the result in the shared state. Any exception propagated from the execution of \tcode{invoke(auto(std::forward(f)), auto(std::forward(args))...)} is stored as the exceptional result in the shared state. The \tcode{thread} object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state. \item If \tcode{launch::deferred} is set in \tcode{policy}, stores \tcode{auto(std::forward(f))} and \tcode{auto(std::for\-ward(args))...} in the shared state. These copies of \tcode{f} and \tcode{args} constitute a \defnadj{deferred}{function}. Invocation of the deferred function evaluates \tcode{invoke(std::move(g), std::move(xyz))} where \tcode{g} is the stored value of \tcode{auto(std::forward(f))} and \tcode{xyz} is the stored copy of \tcode{auto(std::forward(args))...}. Any return value is stored as the result in the shared state. Any exception propagated from the execution of the deferred function is stored as the exceptional result in the shared state. The shared state is not made ready until the function has completed. The first call to a non-timed waiting function\iref{futures.state} on an asynchronous return object referring to this shared state invokes the deferred function in the thread that called the waiting function. Once evaluation of \tcode{invoke(std::move(g), std::move(xyz))} begins, the function is no longer considered deferred. \recommended If this policy is specified together with other policies, such as when using a \tcode{policy} value of \tcode{launch::async | launch::deferred}, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited. \item If no value is set in the launch policy, or a value is set that is neither specified in this document nor by the implementation, the behavior is undefined. \end{itemize} \pnum \sync The invocation of \tcode{async} synchronizes with the invocation of \tcode{f}. The completion of the function \tcode{f} is sequenced before the shared state is made ready. \begin{note} These apply regardless of the provided \tcode{policy} argument, and even if the corresponding \tcode{future} object is moved to another thread. However, it is possible for \tcode{f} not to be called at all, in which case its completion never happens. \end{note} If the implementation chooses the \tcode{launch::async} policy, \begin{itemize} \item a call to a waiting function on an asynchronous return object that shares the shared state created by this \tcode{async} call shall block until the associated thread has completed, as if joined, or else time out\iref{thread.thread.member}; \item the associated thread completion synchronizes with\iref{intro.multithread} the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first. \end{itemize} \pnum \returns An object of type \tcode{future, decay_t...>>} that refers to the shared state created by this call to \tcode{async}. \begin{note} If a future obtained from \tcode{async} is moved outside the local scope, the future's destructor can block for the shared state to become ready. \end{note} \pnum \throws \tcode{system_error} if \tcode{policy == launch::async} and the implementation is unable to start a new thread, or \tcode{std::bad_alloc} if memory for the internal data structures cannot be allocated. \pnum \errors \begin{itemize} \item \tcode{resource_unavailable_try_again} --- if \tcode{policy == launch::async} and the system is unable to start a new thread. \end{itemize} \end{itemdescr} \pnum \begin{example} \begin{codeblock} int work1(int value); int work2(int value); int work(int value) { auto handle = std::async([=]{ return work2(value); }); int tmp = work1(value); return tmp + handle.get(); // \#1 } \end{codeblock} \begin{note} Line \#1 might not result in concurrency because the \tcode{async} call uses the default policy, which might use \tcode{launch::deferred}, in which case the lambda might not be invoked until the \tcode{get()} call; in that case, \tcode{work1} and \tcode{work2} are called on the same thread and there is no concurrency. \end{note} \end{example} \rSec2[futures.task]{Class template \tcode{packaged_task}} \rSec3[futures.task.general]{General} \pnum The class template \tcode{packaged_task} defines a type for wrapping a function or callable object so that the return value of the function or callable object is stored in a future when it is invoked. \pnum When the \tcode{packaged_task} object is invoked, its stored task is invoked and the result (whether normal or exceptional) stored in the shared state. Any futures that share the shared state will then be able to access the stored result. \indexlibraryglobal{packaged_task}% \begin{codeblock} namespace std { template class packaged_task; // \notdef template class packaged_task { public: // construction and destruction packaged_task() noexcept; template explicit packaged_task(F&& f); ~packaged_task(); // no copy packaged_task(const packaged_task&) = delete; packaged_task& operator=(const packaged_task&) = delete; // move support packaged_task(packaged_task&& rhs) noexcept; packaged_task& operator=(packaged_task&& rhs) noexcept; void swap(packaged_task& other) noexcept; bool valid() const noexcept; // result retrieval future get_future(); // execution void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset(); }; template packaged_task(R (*)(ArgTypes...)) -> packaged_task; template packaged_task(F) -> packaged_task<@\seebelow@>; } \end{codeblock} \rSec3[futures.task.members]{Member functions} \indexlibraryctor{packaged_task}% \begin{itemdecl} packaged_task() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects The object has no shared state and no stored task. \end{itemdescr} \indexlibraryctor{packaged_task}% \begin{itemdecl} template explicit packaged_task(F&& f); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cvref_t} is not the same type as \tcode{packaged_task}. \pnum \mandates \tcode{is_invocable_r_v} is \tcode{true}. \pnum \expects Invoking a copy of \tcode{f} behaves the same as invoking \tcode{f}. \pnum \effects Constructs a new \tcode{packaged_task} object with a shared state and initializes the object's stored task with \tcode{std::forward(f)}. \pnum \throws Any exceptions thrown by the copy or move constructor of \tcode{f}, or \tcode{bad_alloc} if memory for the internal data structures cannot be allocated. \end{itemdescr} \indexlibraryctor{packaged_task}% \begin{itemdecl} template packaged_task(F) -> packaged_task<@\seebelow@>; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{\&F::operator()} is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand} and either \begin{itemize} \item \tcode{F::operator()} is a non-static member function and \tcode{decltype(\brk{}\&F::operator())} is either of the form \tcode{R(G::*)(A...)}~\cv{}~\tcode{\opt{\&}~\opt{noexcept}} or of the form \tcode{R(*)(G, A...)~\opt{noexcept}} for a type \tcode{G}, or \item \tcode{F::operator()} is a static member function and \tcode{decltype(\&F::operator())} is of the form \tcode{R(*)(A...) \opt{noexcept}}. \end{itemize} \pnum \remarks The deduced type is \tcode{packaged_task}. \end{itemdescr} \indexlibraryctor{packaged_task}% \begin{itemdecl} packaged_task(packaged_task&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Transfers ownership of \tcode{rhs}'s shared state to \tcode{*this}, leaving \tcode{rhs} with no shared state. Moves the stored task from \tcode{rhs} to \tcode{*this}. \pnum \ensures \tcode{rhs} has no shared state. \end{itemdescr} \indexlibrarymember{operator=}{packaged_task}% \begin{itemdecl} packaged_task& operator=(packaged_task&& rhs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects \begin{itemize} \item Releases any shared state\iref{futures.state}; \item calls \tcode{packaged_task(std::move(rhs)).swap(*this)}. \end{itemize} \end{itemdescr} \indexlibrarydtor{packaged_task}% \begin{itemdecl} ~packaged_task(); \end{itemdecl} \begin{itemdescr} \pnum \effects Abandons any shared state\iref{futures.state}. \end{itemdescr} \indexlibrarymember{swap}{packaged_task}% \begin{itemdecl} void swap(packaged_task& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Exchanges the shared states and stored tasks of \tcode{*this} and \tcode{other}. \pnum \ensures \tcode{*this} has the same shared state and stored task (if any) as \tcode{other} prior to the call to \tcode{swap}. \tcode{other} has the same shared state and stored task (if any) as \tcode{*this} prior to the call to \tcode{swap}. \end{itemdescr} \indexlibrarymember{valid}{packaged_task}% \begin{itemdecl} bool valid() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} only if \tcode{*this} has a shared state. \end{itemdescr} \indexlibrarymember{get_future}{packaged_task}% \begin{itemdecl} future get_future(); \end{itemdecl} \begin{itemdescr} \pnum \sync Calls to this function do not introduce data races~\iref{intro.multithread} with calls to \tcode{operator()} or \tcode{make_ready_at_thread_exit}. \begin{note} Such calls need not synchronize with each other. \end{note} \pnum \returns A \tcode{future} object that shares the same shared state as \tcode{*this}. \pnum \throws A \tcode{future_error} object if an error occurs. \pnum \errors \begin{itemize} \item \tcode{future_already_retrieved} if \tcode{get_future} has already been called on a \tcode{packaged_task} object with the same shared state as \tcode{*this}. \item \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \indexlibrarymember{operator()}{packaged_task}% \begin{itemdecl} void operator()(ArgTypes... args); \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)}\iref{func.require}, where \tcode{f} is the stored task of \tcode{*this} and \tcode{t$_1$, t$_2$, $\dotsc$, t$_N$} are the values in \tcode{args...}. If the task returns normally, the return value is stored as the asynchronous result in the shared state of \tcode{*this}, otherwise the exception thrown by the task is stored. The shared state of \tcode{*this} is made ready, and any threads blocked in a function waiting for the shared state of \tcode{*this} to become ready are unblocked. \pnum \throws A \tcode{future_error} exception object if there is no shared state or the stored task has already been invoked. \pnum \errors \begin{itemize} \item \tcode{promise_already_satisfied} if the stored task has already been invoked. \item \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \indexlibrarymember{make_ready_at_thread_exit}{packaged_task}% \begin{itemdecl} void make_ready_at_thread_exit(ArgTypes... args); \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)}\iref{func.require}, where \tcode{f} is the stored task and \tcode{t$_1$, t$_2$, $\dotsc$, t$_N$} are the values in \tcode{args...}. If the task returns normally, the return value is stored as the asynchronous result in the shared state of \tcode{*this}, otherwise the exception thrown by the task is stored. In either case, this is done without making that state ready\iref{futures.state} immediately. Schedules the shared state to be made ready when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. \pnum \throws \tcode{future_error} if an error condition occurs. \pnum \errors \begin{itemize} \item \tcode{promise_already_satisfied} if the stored task has already been invoked. \item \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \indexlibrarymember{reset}{packaged_task}% \begin{itemdecl} void reset(); \end{itemdecl} \begin{itemdescr} \pnum \effects As if \tcode{*this = packaged_task(std::move(f))}, where \tcode{f} is the task stored in \tcode{*this}. \begin{note} This constructs a new shared state for \tcode{*this}. The old state is abandoned\iref{futures.state}. \end{note} \pnum \throws \begin{itemize} \item \tcode{bad_alloc} if memory for the new shared state cannot be allocated. \item Any exception thrown by the move constructor of the task stored in the shared state. \item \tcode{future_error} with an error condition of \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize} \end{itemdescr} \rSec3[futures.task.nonmembers]{Globals} \indexlibrarymember{swap}{packaged_task}% \begin{itemdecl} template void swap(packaged_task& x, packaged_task& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{x.swap(y)}. \end{itemdescr} \rSec1[saferecl]{Safe reclamation} \rSec2[saferecl.general]{General} \pnum Subclause \ref{saferecl} contains safe-reclamation techniques, which are most frequently used to straightforwardly resolve access-deletion races. \rSec2[saferecl.rcu]{Read-copy update (RCU)} \rSec3[saferecl.rcu.general]{General} \pnum RCU is a synchronization mechanism that can be used for linked data structures that are frequently read, but seldom updated. RCU does not provide mutual exclusion, but instead allows the user to schedule specified actions such as deletion at some later time. \pnum A class type \tcode{T} is \defn{rcu-protectable} if it has exactly one base class of type \tcode{rcu_obj_base} for some \tcode{D}, and that base is public and non-virtual, and it has no base classes of type \tcode{rcu_obj_base} for any other combination \tcode{X}, \tcode{Y}. An object is rcu-protectable if it is of rcu-protectable type. \pnum An invocation of \tcode{unlock} $U$ on an \tcode{rcu_domain dom} corresponds to an invocation of \tcode{lock} $L$ on \tcode{dom} if $L$ is sequenced before $U$ and either \begin{itemize} \item no other invocation of \tcode{lock} on \tcode{dom} is sequenced after $L$ and before $U$, or \item every invocation of \tcode{unlock} $U2$ on \tcode{dom} such that $L$ is sequenced before $U2$ and $U2$ is sequenced before $U$ corresponds to an invocation of \tcode{lock} $L2$ on \tcode{dom} such that $L$ is sequenced before $L2$ and $L2$ is sequenced before $U2$. \end{itemize} \begin{note} This pairs nested locks and unlocks on a given domain in each thread. \end{note} \pnum A \defn{region of RCU protection} on a domain \tcode{dom} starts with a \tcode{lock} $L$ on \tcode{dom} and ends with its corresponding \tcode{unlock} $U$. \pnum Given a region of RCU protection $R$ on a domain \tcode{dom} and given an evaluation $E$ that scheduled another evaluation $F$ in \tcode{dom}, if $E$ does not strongly happen before the start of $R$, the end of $R$ strongly happens before evaluating $F$. \pnum The evaluation of a scheduled evaluation is potentially concurrent with any other scheduled evaluation. Each scheduled evaluation is evaluated at most once. \rSec3[rcu.syn]{Header \tcode{} synopsis} \indexheader{rcu} \begin{codeblock} namespace std { // \ref{saferecl.rcu.base}, class template \tcode{rcu_obj_base} template> class rcu_obj_base; // \ref{saferecl.rcu.domain}, class \tcode{rcu_domain} class rcu_domain; // \ref{saferecl.rcu.domain.func} non-member functions rcu_domain& rcu_default_domain() noexcept; void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept; void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept; template> void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain()); } \end{codeblock} \rSec3[saferecl.rcu.base]{Class template \tcode{rcu_obj_base}} \pnum Objects of type \tcode{T} to be protected by RCU inherit from a specialization \tcode{rcu_obj_base} for some \tcode{D}. \begin{codeblock} namespace std { template> class rcu_obj_base { public: void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept; protected: rcu_obj_base() = default; rcu_obj_base(const rcu_obj_base&) = default; rcu_obj_base(rcu_obj_base&&) = default; rcu_obj_base& operator=(const rcu_obj_base&) = default; rcu_obj_base& operator=(rcu_obj_base&&) = default; ~rcu_obj_base() = default; private: D @\exposid{deleter}@; // \expos }; } \end{codeblock} \pnum The behavior of a program that adds specializations for \tcode{rcu_obj_base} is undefined. \pnum \tcode{T} may be an incomplete type. It shall be complete before any member of the resulting specialization of \tcode{rcu_obj_base} is referenced. \pnum \tcode{D} shall be a function object type\iref{function.objects} for which, given a value \tcode{d} of type \tcode{D} and a value \tcode{ptr} of type \tcode{T*}, the expression \tcode{d(ptr)} is valid. \pnum \tcode{D} shall meet the requirements for \oldconcept{DefaultConstructible} and \oldconcept{MoveAssignable}. \pnum If \tcode{D} is trivially copyable, all specializations of \tcode{rcu_obj_base} are trivially copyable. \begin{itemdecl} void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is an rcu-protectable type. \pnum \expects \tcode{*this} is a base class subobject of an object \tcode{x} of type \tcode{T}. The member function \tcode{rcu_obj_base::retire} was not invoked on \tcode{x} before. The assignment to \exposid{deleter} does not exit via an exception. \pnum \effects Evaluates \tcode{\exposid{deleter} = std::move(d)} and schedules the evaluation of the expression \tcode{\exposid{deleter}(\newline addressof(x))} in the domain \tcode{dom}; the behavior is undefined if that evaluation exits via an exception. May invoke scheduled evaluations in \tcode{dom}. \begin{note} If such evaluations acquire resources held across any invocation of \tcode{retire} on \tcode{dom}, deadlock can occur. \end{note} \end{itemdescr} \rSec3[saferecl.rcu.domain]{Class \tcode{rcu_domain}} \rSec4[saferecl.rcu.domain.general]{General} \begin{codeblock} namespace std { class rcu_domain { public: rcu_domain(const rcu_domain&) = delete; rcu_domain& operator=(const rcu_domain&) = delete; void lock() noexcept; bool try_lock() noexcept; void unlock() noexcept; }; } \end{codeblock} \pnum This class meets the requirements of \oldconcept{Lockable}\iref{thread.req.lockable.req} and provides regions of RCU protection. \begin{example} \begin{codeblock} std::scoped_lock rlock(rcu_default_domain()); \end{codeblock} \end{example} \pnum The functions \tcode{lock} and \tcode{unlock} establish (possibly nested) regions of RCU protection. \rSec4[saferecl.rcu.domain.members]{Member functions} \indexlibrarymember{lock}{rcu_domain}% \begin{itemdecl} void lock() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Opens a region of RCU protection. \pnum \remarks Calls to \tcode{lock} do not introduce a data race\iref{intro.races} involving \tcode{*this}. \end{itemdescr} \indexlibrarymember{try_lock}{rcu_domain}% \begin{itemdecl} bool try_lock() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{lock()}. \pnum \returns \tcode{true}. \end{itemdescr} \indexlibrarymember{unlock}{rcu_domain}% \begin{itemdecl} void unlock() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects A call to \tcode{lock} that opened an unclosed region of RCU protection is sequenced before the call to \tcode{unlock}. \pnum \effects Closes the unclosed region of RCU protection that was most recently opened. May invoke scheduled evaluations in \tcode{*this}. \pnum \begin{note} If such evaluations acquire resources held across any invocation of \tcode{unlock} on \tcode{*this}, deadlock can occur. \end{note} \pnum \remarks Calls to \tcode{unlock} do not introduce a data race involving \tcode{*this}. \begin{note} Evaluation of scheduled evaluations can still cause a data race. \end{note} \end{itemdescr} \rSec4[saferecl.rcu.domain.func]{Non-member functions} \indexlibraryglobal{rcu_default_domain}% \begin{itemdecl} rcu_domain& rcu_default_domain() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A reference to a static-duration object of type \tcode{rcu_domain}. A reference to the same object is returned every time this function is called. \end{itemdescr} \indexlibraryglobal{rcu_synchronize}% \begin{itemdecl} void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If the call to \tcode{rcu_synchronize} does not strongly happen before the lock opening an RCU protection region \tcode{R} on \tcode{dom}, blocks until the \tcode{unlock} closing \tcode{R} happens. \pnum \sync The \tcode{unlock} closing \tcode{R} strongly happens before the return from \tcode{rcu_synchronize}. \end{itemdescr} \indexlibraryglobal{rcu_barrier}% \begin{itemdecl} void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects May evaluate any scheduled evaluations in \tcode{dom}. For any evaluation that happens before the call to \tcode{rcu_barrier} and that schedules an evaluation $E$ in \tcode{dom}, blocks until $E$ has been evaluated. \pnum \sync The evaluation of any such $E$ strongly happens before the return from \tcode{rcu_barrier}. \begin{note} A call to \tcode{rcu_barrier} does not imply a call to \tcode{rcu_synchronize} and vice versa. \end{note} \end{itemdescr} \indexlibraryglobal{rcu_retire}% \begin{itemdecl} template> void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain()); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{is_move_constructible_v} is \tcode{true} and the expression \tcode{d(p)} is well-formed. \pnum \expects \tcode{D} meets the \oldconcept{MoveConstructible} and \oldconcept{Destructible} requirements. \pnum \effects May allocate memory. It is unspecified whether the memory allocation is performed by invoking \tcode{\keyword{operator} \keyword{new}}. Initializes an object \tcode{d1} of type \tcode{D} from \tcode{std::move(d)}. Schedules the evaluation of \tcode{d1(p)} in the domain \tcode{dom}; the behavior is undefined if that evaluation exits via an exception. May invoke scheduled evaluations in \tcode{dom}. \begin{note} If \tcode{rcu_retire} exits via an exception, no evaluation is scheduled. \end{note} \pnum \throws \tcode{bad_alloc} or any exception thrown by the initialization of \tcode{d1}. \pnum \begin{note} If scheduled evaluations acquire resources held across any invocation of \tcode{rcu_retire} on \tcode{dom}, deadlock can occur. \end{note} \end{itemdescr} \rSec2[saferecl.hp]{Hazard pointers} \rSec3[saferecl.hp.general]{General} \pnum \indextext{hazard pointer}% A hazard pointer is a single-writer multi-reader pointer that can be owned by at most one thread at any time. Only the owner of the hazard pointer can set its value, while any number of threads may read its value. The owner thread sets the value of a hazard pointer to point to an object in order to indicate to concurrent threads---which may delete such an object---that the object is not yet safe to delete. \pnum A class type \tcode{T} is \defn{hazard-protectable} if it has exactly one base class of type \tcode{hazard_pointer_obj_base} for some \tcode{D}, that base is public and non-virtual, and it has no base classes of type \tcode{hazard_pointer_obj_base} for any other combination \tcode{T2}, \tcode{D2}. An object is \defn{hazard-protectable} if it is of hazard-protectable type. \pnum The time span between creation and destruction of a hazard pointer $h$ is partitioned into a series of \defnadjx{protection}{epochs}{epoch}; in each protection epoch, $h$ either is \defnx{associated with}{hazard pointer!associated} a hazard-protectable object, or is \defnx{unassociated}{hazard pointer!unassociated}. Upon creation, a hazard pointer is unassociated. Changing the association (possibly to the same object) initiates a new protection epoch and ends the preceding one. \pnum An object \tcode{x} of hazard-protectable type \tcode{T} is \defn{retired} with a deleter of type \tcode{D} when the member function \tcode{hazard_pointer_obj_base::retire} is invoked on \tcode{x}. Any given object \tcode{x} shall be retired at most once. \pnum A retired object \tcode{x} is \defn{reclaimed} by invoking its deleter with a pointer to \tcode{x}; the behavior is undefined if that invocation exits via an exception. \pnum A hazard-protectable object \tcode{x} is \defn{possibly-reclaimable} with respect to an evaluation $A$ if: \begin{itemize} \item \tcode{x} is not reclaimed; and \item \tcode{x} is retired in an evaluation $R$ and $A$ does not happen before $R$; and \item for all hazard pointers $h$ and for every protection epoch $E$ of $h$ during which $h$ is associated with \tcode{x}: \begin{itemize} \item if the beginning of $E$ happens before $R$, the end of $E$ strongly happens before $A$; and \item if $E$ began by an evaluation of \tcode{try_protect} with argument \tcode{src}, label its atomic load operation $L$. If there exists an atomic modification $B$ on \tcode{src} such that $L$ observes a modification that is modification-ordered before $B$, and $B$ happens before \tcode{x} is retired, the end of $E$ strongly happens before $A$. \begin{note} In typical use, a store to \tcode{src} sequenced before retiring \tcode{x} will be such an atomic operation $B$. \end{note} \end{itemize} \begin{note} The latter two conditions convey the informal notion that a protection epoch that began before retiring \tcode{x}, as implied either by the happens-before relation or the coherence order of some source, delays the reclamation of \tcode{x}. \end{note} \end{itemize} \pnum The number of possibly-reclaimable objects has an unspecified bound. \begin{note} The bound can be a function of the number of hazard pointers, the number of threads that retire objects, and the number of threads that use hazard pointers. \end{note} \begin{example} The following example shows how hazard pointers allow updates to be carried out in the presence of concurrent readers. The object of type \tcode{hazard_pointer} in \tcode{print_name} protects the object \tcode{*ptr} from being reclaimed by \tcode{ptr->retire} until the end of the protection epoch. \begin{codeblock} struct Name : public hazard_pointer_obj_base { /* details */ }; atomic name; // called often and in parallel! void print_name() { hazard_pointer h = make_hazard_pointer(); Name* ptr = h.protect(name); // Protection epoch starts // ... safe to access \tcode{*ptr} } // Protection epoch ends. // called rarely, but possibly concurrently with \tcode{print_name} void update_name(Name* new_name) { Name* ptr = name.exchange(new_name); ptr->retire(); } \end{codeblock} \end{example} \rSec3[hazard.pointer.syn]{Header \tcode{} synopsis} \indexheader{hazard_pointer}% \begin{codeblock} namespace std { // \ref{saferecl.hp.base}, class template \tcode{hazard_pointer_obj_base} template> class hazard_pointer_obj_base; // \ref{saferecl.hp.holder}, class \tcode{hazard_pointer} class hazard_pointer; // \ref{saferecl.hp.holder.nonmem}, non-member functions hazard_pointer make_hazard_pointer(); void swap(hazard_pointer&, hazard_pointer&) noexcept; } \end{codeblock} \rSec3[saferecl.hp.base]{Class template \tcode{hazard_pointer_obj_base}} \begin{codeblock} namespace std { template> class hazard_pointer_obj_base { public: void retire(D d = D()) noexcept; protected: hazard_pointer_obj_base() = default; hazard_pointer_obj_base(const hazard_pointer_obj_base&) = default; hazard_pointer_obj_base(hazard_pointer_obj_base&&) = default; hazard_pointer_obj_base& operator=(const hazard_pointer_obj_base&) = default; hazard_pointer_obj_base& operator=(hazard_pointer_obj_base&&) = default; ~hazard_pointer_obj_base() = default; private: D @\exposid{deleter}@; // \expos }; } \end{codeblock} \pnum \tcode{D} shall be a function object type\iref{func.require} for which, given a value \tcode{d} of type \tcode{D} and a value \tcode{ptr} of type \tcode{T*}, the expression \tcode{d(ptr)} is valid. \pnum The behavior of a program that adds specializations for \tcode{hazard_pointer_obj_base} is undefined. \pnum \tcode{D} shall meet the requirements for \oldconcept{DefaultConstructible} and \oldconcept{MoveAssignable}. \pnum \tcode{T} may be an incomplete type. It shall be complete before any member of the resulting specialization of \tcode{hazard_pointer_obj_base} is referenced. \indexlibrarymember{retire}{hazard_pointer_obj_base}% \begin{itemdecl} void retire(D d = D()) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a hazard-protectable type. \pnum \expects \tcode{*this} is a base class subobject of an object \tcode{x} of type \tcode{T}. \tcode{x} is not retired. Move-assigning \tcode{d} to \tcode{deleter} does not exit via an exception. \pnum \effects Move-assigns \tcode{d} to \tcode{deleter}, thereby setting it as the deleter of \tcode{x}, then retires \tcode{x}. May reclaim possibly-reclaimable objects. \end{itemdescr} \rSec3[saferecl.hp.holder]{Class \tcode{hazard_pointer}} \rSec4[saferecl.hp.holder.general]{General} \begin{codeblock} namespace std { class hazard_pointer { public: hazard_pointer() noexcept; hazard_pointer(hazard_pointer&&) noexcept; hazard_pointer& operator=(hazard_pointer&&) noexcept; ~hazard_pointer(); [[nodiscard]] bool empty() const noexcept; template T* protect(const atomic& src) noexcept; template bool try_protect(T*& ptr, const atomic& src) noexcept; template void reset_protection(const T* ptr) noexcept; void reset_protection(nullptr_t = nullptr) noexcept; void swap(hazard_pointer&) noexcept; }; } \end{codeblock} \pnum An object of type \tcode{hazard_pointer} is either empty or \defnx{owns}{owning!hazard pointer} a hazard pointer. Each hazard pointer is owned by exactly one object of type \tcode{hazard_pointer}. \begin{note} An empty \tcode{hazard_pointer} object is different from a \tcode{hazard_pointer} object that owns an unassociated hazard pointer. An empty \tcode{hazard_pointer} object does not own any hazard pointers. \end{note} \rSec4[saferecl.hp.holder.ctor]{Constructors, destructor, and assignment} \indexlibraryctor{hazard_pointer}% \begin{itemdecl} hazard_pointer() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{*this} is empty. \end{itemdescr} \indexlibraryctor{hazard_pointer}% \begin{itemdecl} hazard_pointer(hazard_pointer&& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures If \tcode{other} is empty, \tcode{*this} is empty. Otherwise, \tcode{*this} owns the hazard pointer originally owned by \tcode{other}; \tcode{other} is empty. \end{itemdescr} \indexlibrarydtor{hazard_pointer}% \begin{itemdecl} ~hazard_pointer(); \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{*this} is not empty, destroys the hazard pointer owned by \tcode{*this}, thereby ending its current protection epoch. \end{itemdescr} \indexlibrarymember{operator=}{hazard_pointer}% \begin{itemdecl} hazard_pointer& operator=(hazard_pointer&& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{this == \&other} is \tcode{true}, no effect. Otherwise, if \tcode{*this} is not empty, destroys the hazard pointer owned by \tcode{*this}, thereby ending its current protection epoch. \pnum \ensures If \tcode{other} was empty, \tcode{*this} is empty. Otherwise, \tcode{*this} owns the hazard pointer originally owned by \tcode{other}. If \tcode{this != \&other} is \tcode{true}, \tcode{other} is empty. \pnum \returns \tcode{*this}. \end{itemdescr} \rSec4[saferecl.hp.holder.mem]{Member functions} \indexlibrarymember{empty}{hazard_pointer}% \begin{itemdecl} [[nodiscard]] bool empty() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if and only if \tcode{*this} is empty. \end{itemdescr} \indexlibrarymember{protect}{hazard_pointer}% \begin{itemdecl} template T* protect(const atomic& src) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} T* ptr = src.load(memory_order::relaxed); while (!try_protect(ptr, src)) {} return ptr; \end{codeblock} \end{itemdescr} \indexlibrarymember{try_protect}{hazard_pointer}% \begin{itemdecl} template bool try_protect(T*& ptr, const atomic& src) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a hazard-protectable type. \pnum \expects \tcode{*this} is not empty. \pnum \effects Performs the following steps in order: \begin{itemize} \item Initializes a variable \tcode{old} of type \tcode{T*} with the value of \tcode{ptr}. \item Evaluates \tcode{reset_protection(old)}. \item Assigns the value of \tcode{src.load(memory_order::acquire)} to \tcode{ptr}. \item If \tcode{old == ptr} is \tcode{false}, evaluates \tcode{reset_protection()}. \end{itemize} \pnum \returns \tcode{old == ptr}. \end{itemdescr} \indexlibrarymember{reset_protection}{hazard_pointer}% \begin{itemdecl} template void reset_protection(const T* ptr) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a hazard-protectable type. \pnum \expects \tcode{*this} is not empty. \pnum \effects If \tcode{ptr} is a null pointer value, invokes \tcode{reset_protection()}. Otherwise, associates the hazard pointer owned by \tcode{*this} with \tcode{*ptr}, thereby ending the current protection epoch. \pnum \complexity Constant. \end{itemdescr} \indexlibrarymember{reset_protection}{hazard_pointer}% \begin{itemdecl} void reset_protection(nullptr_t = nullptr) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{*this} is not empty. \pnum \ensures The hazard pointer owned by \tcode{*this} is unassociated. \pnum \complexity Constant. \end{itemdescr} \indexlibrarymember{swap}{hazard_pointer}% \begin{itemdecl} void swap(hazard_pointer& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Swaps the hazard pointer ownership of this object with that of \tcode{other}. \begin{note} The owned hazard pointers, if any, remain unchanged during the swap and continue to be associated with the respective objects that they were protecting before the swap, if any. No protection epochs are ended or initiated. \end{note} \pnum \complexity Constant. \end{itemdescr} \rSec4[saferecl.hp.holder.nonmem]{Non-member functions} \indexlibraryglobal{make_hazard_pointer}% \begin{itemdecl} hazard_pointer make_hazard_pointer(); \end{itemdecl} \begin{itemdescr} \pnum \effects Constructs a hazard pointer. \pnum \returns A \tcode{hazard_pointer} object that owns the newly-constructed hazard pointer. \pnum \throws May throw \tcode{bad_alloc} if memory for the hazard pointer could not be allocated. \end{itemdescr} \indexlibrarymember{swap}{hazard_pointer}% \begin{itemdecl} void swap(hazard_pointer& a, hazard_pointer& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{a.swap(b)}. \end{itemdescr}