32 Thread support library [thread]

32.1 General [thread.general]

The following subclauses describe components to create and manage threads, perform mutual exclusion, and communicate conditions and values between threads, as summarized in Table 146.
Table 146: Thread support library summary [tab:thread.summary]
Subclause
Header
Requirements
Stop tokens
<stop_­token>
Threads
<thread>
Mutual exclusion
<mutex>, <shared_­mutex>
Condition variables
<condition_­variable>
Semaphores
<semaphore>
Coordination types
<latch> <barrier>
Futures
<future>

32.2 Requirements [thread.req]

32.2.1 Template parameter names [thread.req.paramname]

Throughout this Clause, the names of template parameters are used to express type requirements.
If a template parameter is named Predicate, operator() applied to the template argument shall return a value that is convertible to bool.
If a template parameter is named Clock, the corresponding template argument shall be a type C for which is_­clock_­v<C> is true; otherwise the program is ill-formed.

32.2.2 Exceptions [thread.req.exception]

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

32.2.3 Native handles [thread.req.native]

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

32.2.4 Timing specifications [thread.req.timing]

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

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

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

An execution agent is an entity such as a thread that may perform work in parallel with other execution agents.
[Note 1:
Implementations or users can introduce other kinds of agents such as processes or thread-pool tasks.
โ€” end note]
The calling agent is determined by context, e.g., the calling thread that contains the call, and so on.
[Note 2:
Some lockable objects are โ€œagent obliviousโ€ in that they work for any execution agent model because they do not determine or store the agent's ID (e.g., an ordinary spin lock).
โ€” end note]
The standard library templates unique_­lock ([thread.lock.unique]), shared_­lock ([thread.lock.shared]), scoped_­lock ([thread.lock.scoped]), lock_­guard ([thread.lock.guard]), lock, try_­lock ([thread.lock.algorithm]), and condition_­variable_­any ([thread.condition.condvarany]) all operate on user-supplied lockable objects.
The Cpp17BasicLockable requirements, the Cpp17Lockable requirements, and the Cpp17TimedLockable requirements list the requirements imposed by these library types in order to acquire or release ownership of a lock by a given execution agent.
[Note 3:
The nature of any lock ownership and any synchronization it entails are not part of these requirements.
โ€” end note]

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

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

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

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

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

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

32.3 Stop tokens [thread.stoptoken]

32.3.1 Introduction [thread.stoptoken.intro]

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

32.3.2 Header <stop_­token> synopsis [thread.stoptoken.syn]

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

32.3.3 Class stop_­token [stoptoken]

32.3.3.1 General [stoptoken.general]

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

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

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

32.3.3.3 Members [stoptoken.mem]

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

32.3.3.4 Non-member functions [stoptoken.nonmembers]

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

32.3.4 Class stop_­source [stopsource]

32.3.4.1 General [stopsource.general]

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

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

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

32.3.4.3 Members [stopsource.mem]

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

32.3.4.4 Non-member functions [stopsource.nonmembers]

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

32.3.5 Class template stop_­callback [stopcallback]

32.3.5.1 General [stopcallback.general]

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

32.3.5.2 Constructors and destructor [stopcallback.cons]

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

32.4 Threads [thread.threads]

32.4.1 General [thread.threads.general]

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

32.4.2 Header <thread> synopsis [thread.syn]

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

32.4.3 Class thread [thread.thread.class]

32.4.3.1 General [thread.thread.class.general]

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

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

namespace std { class thread::id { public: id() noexcept; }; bool operator==(thread::id x, thread::id y) noexcept; strong_ordering operator<=>(thread::id x, thread::id y) noexcept; template<class charT, class traits> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& out, thread::id id); // hash support template<class T> struct hash; template<> struct hash<thread::id>; }
An object of type thread​::​id provides a unique identifier for each thread of execution and a single distinct value for all thread objects that do not represent a thread of execution ([thread.thread.class]).
Each thread of execution has an associated thread​::​id object that is not equal to the thread​::​id object of any other thread of execution and that is not equal to the thread​::​id object of any thread object that does not represent threads of execution.
thread​::​id is a trivially copyable class ([class.prop]).
The library may reuse the value of a thread​::​id of a terminated thread that can no longer be joined.
[Note 1:
Relational operators allow thread​::​id objects to be used as keys in associative containers.
โ€” end note]
id() noexcept;
Postconditions: The constructed object does not represent a thread of execution.
bool operator==(thread::id x, thread::id y) noexcept;
Returns: true only if x and y represent the same thread of execution or neither x nor y represents a thread of execution.
strong_ordering operator<=>(thread::id x, thread::id y) noexcept;
Let be an unspecified total ordering over thread​::​id as described in [alg.sorting].
Returns: strong_­ordering​::​less if is true.
Otherwise, strong_­ordering​::​greater if is true.
Otherwise, strong_­ordering​::​equal.
template<class charT, class traits> basic_ostream<charT, traits>& operator<< (basic_ostream<charT, traits>& out, thread::id id);
Effects: Inserts an unspecified text representation of id into out.
For two objects of type thread​::​id x and y, if x == y the thread​::​id objects have the same text representation and if x != y the thread​::​id objects have distinct text representations.
Returns: out.
template<> struct hash<thread::id>;
The specialization is enabled ([unord.hash]).

32.4.3.3 Constructors [thread.thread.constr]

thread() noexcept;
Effects: The object does not represent a thread of execution.
Postconditions: get_­id() == id().
template<class F, class... Args> explicit thread(F&& f, Args&&... args);
Constraints: remove_­cvref_­t<F> is not the same type as thread.
Mandates: The following are all true:
  • is_­constructible_­v<decay_­t<F>, F>,
  • (is_­constructible_­v<decay_­t<Args>, Args> && ...),
  • is_­move_­constructible_­v<decay_­t<F>>,
  • (is_­move_­constructible_­v<decay_­t<Args>> && ...), and
  • is_­invocable_­v<decay_­t<F>, decay_­t<Args>...>.
Preconditions: decay_­t<F> and each type in decay_­t<Args> meet the Cpp17MoveConstructible requirements.
Effects: The new thread of execution executes invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...) with the calls to decay-copy being evaluated in the constructing thread.
Any return value from this invocation is ignored.
[Note 1:
This implies that any exceptions not thrown from the invocation of the copy of f will be thrown in the constructing thread, not the new thread.
โ€” end note]
If the invocation of invoke terminates with an uncaught exception, terminate is called.
Synchronization: The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of f.
Postconditions: get_­id() != id().
*this represents the newly started thread.
Throws: system_­error if unable to start the new thread.
Error conditions:
  • resource_­unavailable_­try_­again โ€” the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.
thread(thread&& x) noexcept;
Postconditions: x.get_­id() == id() and get_­id() returns the value of x.get_­id() prior to the start of construction.

32.4.3.4 Destructor [thread.thread.destr]

~thread();
Effects: If joinable(), calls terminate().
Otherwise, has no effects.
[Note 1:
Either implicitly detaching or joining a joinable() thread in its destructor could 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]

32.4.3.5 Assignment [thread.thread.assign]

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

32.4.3.6 Members [thread.thread.member]

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

32.4.3.7 Static members [thread.thread.static]

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

32.4.3.8 Specialized algorithms [thread.thread.algorithm]

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

32.4.4 Class jthread [thread.jthread.class]

32.4.4.1 General [thread.jthread.class.general]

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

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

jthread() noexcept;
Effects: Constructs a jthread object that does not represent a thread of execution.
Postconditions: get_­id() == id() is true and ssource.stop_­possible() is false.
template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
Constraints: remove_­cvref_­t<F> is not the same type as jthread.
Mandates: The following are all true:
  • is_­constructible_­v<decay_­t<F>, F>,
  • (is_­constructible_­v<decay_­t<Args>, Args> && ...),
  • is_­move_­constructible_­v<decay_­t<F>>,
  • (is_­move_­constructible_­v<decay_­t<Args>> && ...), and
  • is_­invocable_­v<decay_­t<F>, decay_­t<Args>...> ||
    is_­invocable_­v<decay_­t<F>, stop_­token, decay_­t<Args>...>.
Preconditions: decay_­t<F> and each type in decay_­t<Args> meet the Cpp17MoveConstructible requirements.
Effects: Initializes ssource.
The new thread of execution executes invoke(decay-copy(std::forward<F>(f)), get_stop_token(), decay-copy(std::forward<Args>(args))...) if that expression is well-formed, otherwise invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...) with the calls to decay-copy being evaluated in the constructing thread.
Any return value from this invocation is ignored.
[Note 1:
This implies that any exceptions not thrown from the invocation of the copy of f will be thrown in the constructing thread, not the new thread.
โ€” end note]
If the invoke expression exits via an exception, terminate is called.
Synchronization: The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of f.
Postconditions: get_­id() != id() is true and ssource.stop_­possible() is true and *this represents the newly started thread.
[Note 2:
The calling thread can make a stop request only once, because it cannot replace this stop token.
โ€” end note]
Throws: system_­error if unable to start the new thread.
Error conditions:
  • resource_­unavailable_­try_­again โ€” the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.
jthread(jthread&& x) noexcept;
Postconditions: x.get_­id() == id() and get_­id() returns the value of x.get_­id() prior to the start of construction.
ssource has the value of x.ssource prior to the start of construction and x.ssource.stop_­possible() is false.
~jthread();
Effects: If joinable() is true, calls request_­stop() and then join().
[Note 3:
Operations on *this are not synchronized.
โ€” end note]
jthread& operator=(jthread&& x) noexcept;
Effects: If joinable() is true, calls request_­stop() and then join().
Assigns the state of x to *this and sets x to a default constructed state.
Postconditions: x.get_­id() == id() and get_­id() returns the value of x.get_­id() prior to the assignment.
ssource has the value of x.ssource prior to the assignment and x.ssource.stop_­possible() is false.
Returns: *this.

32.4.4.3 Members [thread.jthread.mem]

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

32.4.4.4 Stop token handling [thread.jthread.stop]

[[nodiscard]] stop_source get_stop_source() noexcept;
Effects: Equivalent to: return ssource;
[[nodiscard]] stop_token get_stop_token() const noexcept;
Effects: Equivalent to: return ssource.get_­token();
bool request_stop() noexcept;
Effects: Equivalent to: return ssource.request_­stop();

32.4.4.5 Specialized algorithms [thread.jthread.special]

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

32.4.4.6 Static members [thread.jthread.static]

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

32.4.5 Namespace this_­thread [thread.thread.this]

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

32.5 Mutual exclusion [thread.mutex]

32.5.1 General [thread.mutex.general]

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

32.5.2 Header <mutex> synopsis [mutex.syn]

namespace std { class mutex; class recursive_mutex; class 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 { }; template<class Mutex> class lock_guard; template<class... MutexTypes> class scoped_lock; template<class Mutex> class unique_lock; template<class Mutex> void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept; template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...); template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...); struct once_flag; template<class Callable, class... Args> void call_once(once_flag& flag, Callable&& func, Args&&... args); }

32.5.3 Header <shared_­mutex> synopsis [shared.mutex.syn]

namespace std { class shared_mutex; class shared_timed_mutex; template<class Mutex> class shared_lock; template<class Mutex> void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept; }

32.5.4 Mutex requirements [thread.mutex.requirements]

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

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

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

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

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

32.5.4.2.2 Class mutex [thread.mutex.class]

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

32.5.4.2.3 Class recursive_­mutex [thread.mutex.recursive]

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

32.5.4.3 Timed mutex types [thread.timedmutex.requirements]

32.5.4.3.1 General [thread.timedmutex.requirements.general]

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

32.5.4.3.2 Class timed_­mutex [thread.timedmutex.class]

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

32.5.4.3.3 Class recursive_­timed_­mutex [thread.timedmutex.recursive]

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

32.5.4.4 Shared mutex types [thread.sharedmutex.requirements]

32.5.4.4.1 General [thread.sharedmutex.requirements.general]

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

32.5.4.4.2 Class shared_­mutex [thread.sharedmutex.class]

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

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

32.5.4.5.1 General [thread.sharedtimedmutex.requirements.general]

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

32.5.4.5.2 Class shared_­timed_­mutex [thread.sharedtimedmutex.class]

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

32.5.5 Locks [thread.lock]

32.5.5.1 General [thread.lock.general]

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

32.5.5.2 Class template lock_­guard [thread.lock.guard]

namespace std { template<class Mutex> class lock_guard { public: using mutex_type = Mutex; explicit lock_guard(mutex_type& m); lock_guard(mutex_type& m, adopt_lock_t); ~lock_guard(); lock_guard(const lock_guard&) = delete; lock_guard& operator=(const lock_guard&) = delete; private: mutex_type& pm; // exposition only }; }
An object of type lock_­guard controls the ownership of a lockable object within a scope.
A lock_­guard object maintains ownership of a lockable object throughout the lock_­guard object's lifetime.
The behavior of a program is undefined if the lockable object referenced by pm does not exist for the entire lifetime of the lock_­guard object.
The supplied Mutex type shall meet the Cpp17BasicLockable requirements ([thread.req.lockable.basic]).
explicit lock_guard(mutex_type& m);
Preconditions: If mutex_­type is not a recursive mutex, the calling thread does not own the mutex m.
Effects: Initializes pm with m.
Calls m.lock().
lock_guard(mutex_type& m, adopt_lock_t);
Preconditions: The calling thread owns the mutex m.
Effects: Initializes pm with m.
Throws: Nothing.
~lock_guard();
Effects: As if by pm.unlock().

32.5.5.3 Class template scoped_­lock [thread.lock.scoped]

namespace std { template<class... MutexTypes> class scoped_lock { public: using mutex_type = Mutex; // If MutexTypes... consists of the single type Mutex 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<MutexTypes&...> pm; // exposition only }; }
An object of type scoped_­lock controls the ownership of lockable objects within a scope.
A scoped_­lock object maintains ownership of lockable objects throughout the scoped_­lock object's lifetime.
The behavior of a program is undefined if the lockable objects referenced by pm do not exist for the entire lifetime of the scoped_­lock object.
When sizeof...(MutexTypes) is 1, the supplied Mutex type shall meet the Cpp17BasicLockable requirements ([thread.req.lockable.basic]).
Otherwise, each of the mutex types shall meet the Cpp17Lockable requirements ([thread.req.lockable.req]).
explicit scoped_lock(MutexTypes&... m);
Preconditions: If a MutexTypes type is not a recursive mutex, the calling thread does not own the corresponding mutex element of m.
Effects: Initializes pm with tie(m...).
Then if sizeof...(MutexTypes) is 0, no effects.
Otherwise if sizeof...(MutexTypes) is 1, then m.lock().
Otherwise, lock(m...).
explicit scoped_lock(adopt_lock_t, MutexTypes&... m);
Preconditions: The calling thread owns all the mutexes in m.
Effects: Initializes pm with tie(m...).
Throws: Nothing.
~scoped_lock();
Effects: For all i in [0, sizeof...(MutexTypes)), get<i>(pm).unlock().

32.5.5.4 Class template unique_­lock [thread.lock.unique]

32.5.5.4.1 General [thread.lock.unique.general]

namespace std { template<class Mutex> class unique_lock { public: using mutex_type = Mutex; // [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<class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& 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); // [thread.lock.unique.locking], locking void lock(); bool try_lock(); template<class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // [thread.lock.unique.mod], modifiers void swap(unique_lock& u) noexcept; mutex_type* release() noexcept; // [thread.lock.unique.obs], observers bool owns_lock() const noexcept; explicit operator bool () const noexcept; mutex_type* mutex() const noexcept; private: mutex_type* pm; // exposition only bool owns; // exposition only }; template<class Mutex> void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept; }
An object of type 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 unique_­lock object.
Objects of type unique_­lock are not copyable but are movable.
The behavior of a program is undefined if the contained pointer pm is not null and the lockable object pointed to by pm does not exist for the entire remaining lifetime ([basic.life]) of the unique_­lock object.
The supplied Mutex type shall meet the Cpp17BasicLockable requirements ([thread.req.lockable.basic]).
[Note 1:
unique_­lock<Mutex> meets the Cpp17BasicLockable requirements.
If Mutex meets the Cpp17Lockable requirements ([thread.req.lockable.req]), unique_­lock<Mutex> also meets the Cpp17Lockable requirements; if Mutex meets the Cpp17TimedLockable requirements ([thread.req.lockable.timed]), unique_­lock<Mutex> also meets the Cpp17TimedLockable requirements.
โ€” end note]

32.5.5.4.2 Constructors, destructor, and assignment [thread.lock.unique.cons]

unique_lock() noexcept;
Postconditions: pm == 0 and owns == false.
explicit unique_lock(mutex_type& m);
Preconditions: If mutex_­type is not a recursive mutex the calling thread does not own the mutex.
Effects: Calls m.lock().
Postconditions: pm == addressof(m) and owns == true.
unique_lock(mutex_type& m, defer_lock_t) noexcept;
Postconditions: pm == addressof(m) and owns == false.
unique_lock(mutex_type& m, try_to_lock_t);
Preconditions: The supplied Mutex type meets the Cpp17Lockable requirements ([thread.req.lockable.req]).
If mutex_­type is not a recursive mutex the calling thread does not own the mutex.
Effects: Calls m.try_­lock().
Postconditions: pm == addressof(m) and owns == res, where res is the value returned by the call to m.try_­lock().
unique_lock(mutex_type& m, adopt_lock_t);
Preconditions: The calling thread owns the mutex.
Postconditions: pm == addressof(m) and owns == true.
Throws: Nothing.
template<class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
Preconditions: If mutex_­type is not a recursive mutex the calling thread does not own the mutex.
The supplied Mutex type meets the Cpp17TimedLockable requirements ([thread.req.lockable.timed]).
Effects: Calls m.try_­lock_­until(abs_­time).
Postconditions: pm == addressof(m) and owns == res, where res is the value returned by the call to m.try_­lock_­until(abs_­time).
template<class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
Preconditions: If mutex_­type is not a recursive mutex the calling thread does not own the mutex.
The supplied Mutex type meets the Cpp17TimedLockable requirements ([thread.req.lockable.timed]).
Effects: Calls m.try_­lock_­for(rel_­time).
Postconditions: pm == addressof(m) and owns == res, where res is the value returned by the call to m.try_­lock_­for(rel_­time).
unique_lock(unique_lock&& u) noexcept;
Postconditions: pm == u_­p.pm and owns == u_­p.owns (where u_­p is the state of u just prior to this construction), u.pm == 0 and u.owns == false.
unique_lock& operator=(unique_lock&& u);
Effects: If owns calls pm->unlock().
Postconditions: pm == u_­p.pm and owns == u_­p.owns (where u_­p is the state of u just prior to this construction), u.pm == 0 and u.owns == false.
[Note 1:
With a recursive mutex it is possible for both *this and u to own the same mutex before the assignment.
In this case, *this will own the mutex after the assignment and u will not.
โ€” end note]
Throws: Nothing.
~unique_lock();
Effects: If owns calls pm->unlock().

32.5.5.4.3 Locking [thread.lock.unique.locking]

void lock();
Effects: As if by pm->lock().
Postconditions: owns == true.
Throws: Any exception thrown by pm->lock().
system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if pm is nullptr.
  • resource_­deadlock_­would_­occur โ€” if on entry owns is true.
bool try_lock();
Preconditions: The supplied Mutex meets the Cpp17Lockable requirements ([thread.req.lockable.req]).
Effects: As if by pm->try_­lock().
Postconditions: owns == res, where res is the value returned by the call to try_­lock().
Returns: The value returned by the call to try_­lock().
Throws: Any exception thrown by pm->try_­lock().
system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if pm is nullptr.
  • resource_­deadlock_­would_­occur โ€” if on entry owns is true.
template<class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
Preconditions: The supplied Mutex type meets the Cpp17TimedLockable requirements ([thread.req.lockable.timed]).
Effects: As if by pm->try_­lock_­until(abs_­time).
Postconditions: owns == res, where res is the value returned by the call to try_­lock_­until(abs_­time).
Returns: The value returned by the call to try_­lock_­until(abs_­time).
Throws: Any exception thrown by pm->try_­lock_­until().
system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if pm is nullptr.
  • resource_­deadlock_­would_­occur โ€” if on entry owns is true.
template<class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
Preconditions: The supplied Mutex type meets the Cpp17TimedLockable requirements ([thread.req.lockable.timed]).
Effects: As if by pm->try_­lock_­for(rel_­time).
Postconditions: owns == res, where res is the value returned by the call to try_­lock_­for(rel_­time).
Returns: The value returned by the call to try_­lock_­for(rel_­time).
Throws: Any exception thrown by pm->try_­lock_­for().
system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if pm is nullptr.
  • resource_­deadlock_­would_­occur โ€” if on entry owns is true.
void unlock();
Effects: As if by pm->unlock().
Postconditions: owns == false.
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if on entry owns is false.

32.5.5.4.4 Modifiers [thread.lock.unique.mod]

void swap(unique_lock& u) noexcept;
Effects: Swaps the data members of *this and u.
mutex_type* release() noexcept;
Postconditions: pm == 0 and owns == false.
Returns: The previous value of pm.
template<class Mutex> void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
Effects: As if by x.swap(y).

32.5.5.4.5 Observers [thread.lock.unique.obs]

bool owns_lock() const noexcept;
Returns: owns.
explicit operator bool() const noexcept;
Returns: owns.
mutex_type *mutex() const noexcept;
Returns: pm.

32.5.5.5 Class template shared_­lock [thread.lock.shared]

32.5.5.5.1 General [thread.lock.shared.general]

namespace std { template<class Mutex> class shared_lock { public: using mutex_type = Mutex; // [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<class Clock, class Duration> shared_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time); template<class Rep, class Period> shared_lock(mutex_type& m, const chrono::duration<Rep, Period>& 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; // [thread.lock.shared.locking], locking void lock(); // blocking bool try_lock(); template<class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); // [thread.lock.shared.mod], modifiers void swap(shared_lock& u) noexcept; mutex_type* release() noexcept; // [thread.lock.shared.obs], observers bool owns_lock() const noexcept; explicit operator bool () const noexcept; mutex_type* mutex() const noexcept; private: mutex_type* pm; // exposition only bool owns; // exposition only }; template<class Mutex> void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept; }
An object of type 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 shared_­lock object.
Objects of type shared_­lock are not copyable but are movable.
The behavior of a program is undefined if the contained pointer pm is not null and the lockable object pointed to by pm does not exist for the entire remaining lifetime ([basic.life]) of the shared_­lock object.
The supplied Mutex type shall meet the shared mutex requirements ([thread.sharedtimedmutex.requirements]).
[Note 1:
shared_­lock<Mutex> meets the Cpp17TimedLockable requirements ([thread.req.lockable.timed]).
โ€” end note]

32.5.5.5.2 Constructors, destructor, and assignment [thread.lock.shared.cons]

shared_lock() noexcept;
Postconditions: pm == nullptr and owns == false.
explicit shared_lock(mutex_type& m);
Preconditions: The calling thread does not own the mutex for any ownership mode.
Effects: Calls m.lock_­shared().
Postconditions: pm == addressof(m) and owns == true.
shared_lock(mutex_type& m, defer_lock_t) noexcept;
Postconditions: pm == addressof(m) and owns == false.
shared_lock(mutex_type& m, try_to_lock_t);
Preconditions: The calling thread does not own the mutex for any ownership mode.
Effects: Calls m.try_­lock_­shared().
Postconditions: pm == addressof(m) and owns == res where res is the value returned by the call to m.try_­lock_­shared().
shared_lock(mutex_type& m, adopt_lock_t);
Preconditions: The calling thread has shared ownership of the mutex.
Postconditions: pm == addressof(m) and owns == true.
template<class Clock, class Duration> shared_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
Preconditions: The calling thread does not own the mutex for any ownership mode.
Effects: Calls m.try_­lock_­shared_­until(abs_­time).
Postconditions: pm == addressof(m) and owns == res where res is the value returned by the call to m.try_­lock_­shared_­until(abs_­time).
template<class Rep, class Period> shared_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
Preconditions: The calling thread does not own the mutex for any ownership mode.
Effects: Calls m.try_­lock_­shared_­for(rel_­time).
Postconditions: pm == addressof(m) and owns == res where res is the value returned by the call to m.try_­lock_­shared_­for(rel_­time).
~shared_lock();
Effects: If owns calls pm->unlock_­shared().
shared_lock(shared_lock&& sl) noexcept;
Postconditions: pm == sl_­p.pm and owns == sl_­p.owns (where sl_­p is the state of sl just prior to this construction), sl.pm == nullptr and sl.owns == false.
shared_lock& operator=(shared_lock&& sl) noexcept;
Effects: If owns calls pm->unlock_­shared().
Postconditions: pm == sl_­p.pm and owns == sl_­p.owns (where sl_­p is the state of sl just prior to this assignment), sl.pm == nullptr and sl.owns == false.

32.5.5.5.3 Locking [thread.lock.shared.locking]

void lock();
Effects: As if by pm->lock_­shared().
Postconditions: owns == true.
Throws: Any exception thrown by pm->lock_­shared().
system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if pm is nullptr.
  • resource_­deadlock_­would_­occur โ€” if on entry owns is true.
bool try_lock();
Effects: As if by pm->try_­lock_­shared().
Postconditions: owns == res, where res is the value returned by the call to pm->try_­lock_­shared().
Returns: The value returned by the call to pm->try_­lock_­shared().
Throws: Any exception thrown by pm->try_­lock_­shared().
system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if pm is nullptr.
  • resource_­deadlock_­would_­occur โ€” if on entry owns is true.
template<class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
Effects: As if by pm->try_­lock_­shared_­until(abs_­time).
Postconditions: owns == res, where res is the value returned by the call to pm->try_­lock_­shared_­until(abs_­time).
Returns: The value returned by the call to pm->try_­lock_­shared_­until(abs_­time).
Throws: Any exception thrown by pm->try_­lock_­shared_­until(abs_­time).
system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if pm is nullptr.
  • resource_­deadlock_­would_­occur โ€” if on entry owns is true.
template<class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
Effects: As if by pm->try_­lock_­shared_­for(rel_­time).
Postconditions: owns == res, where res is the value returned by the call to pm->try_­lock_­shared_­for(rel_­time).
Returns: The value returned by the call to pm->try_­lock_­shared_­for(rel_­time).
Throws: Any exception thrown by pm->try_­lock_­shared_­for(rel_­time).
system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if pm is nullptr.
  • resource_­deadlock_­would_­occur โ€” if on entry owns is true.
void unlock();
Effects: As if by pm->unlock_­shared().
Postconditions: owns == false.
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • operation_­not_­permitted โ€” if on entry owns is false.

32.5.5.5.4 Modifiers [thread.lock.shared.mod]

void swap(shared_lock& sl) noexcept;
Effects: Swaps the data members of *this and sl.
mutex_type* release() noexcept;
Postconditions: pm == nullptr and owns == false.
Returns: The previous value of pm.
template<class Mutex> void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
Effects: As if by x.swap(y).

32.5.5.5.5 Observers [thread.lock.shared.obs]

bool owns_lock() const noexcept;
Returns: owns.
explicit operator bool() const noexcept;
Returns: owns.
mutex_type* mutex() const noexcept;
Returns: pm.

32.5.6 Generic locking algorithms [thread.lock.algorithm]

template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
Preconditions: Each template parameter type meets the Cpp17Lockable requirements.
[Note 1:
The unique_­lock class template meets these requirements when suitably instantiated.
โ€” end note]
Effects: Calls try_­lock() for each argument in order beginning with the first until all arguments have been processed or a call to try_­lock() fails, either by returning false or by throwing an exception.
If a call to try_­lock() fails, unlock() is called for all prior arguments with no further calls to try_­lock().
Returns: -1 if all calls to try_­lock() returned true, otherwise a zero-based index value that indicates the argument for which try_­lock() returned false.
template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
Preconditions: Each template parameter type meets the Cpp17Lockable requirements.
[Note 2:
The unique_­lock class template meets these requirements when suitably instantiated.
โ€” end note]
Effects: All arguments are locked via a sequence of calls to lock(), try_­lock(), or unlock() on each argument.
The sequence of calls does not result in deadlock, but is otherwise unspecified.
[Note 3:
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 lock() or try_­lock() throws an exception, unlock() is called for any argument that had been locked by a call to lock() or try_­lock().

32.5.7 Call once [thread.once]

32.5.7.1 Struct once_­flag [thread.once.onceflag]

namespace std { struct once_flag { constexpr once_flag() noexcept; once_flag(const once_flag&) = delete; once_flag& operator=(const once_flag&) = delete; }; }
The class once_­flag is an opaque data structure that call_­once uses to initialize data without causing a data race or deadlock.
constexpr once_flag() noexcept;
Synchronization: The construction of a once_­flag object is not synchronized.
Postconditions: The object's internal state is set to indicate to an invocation of call_­once with the object as its initial argument that no function has been called.

32.5.7.2 Function call_­once [thread.once.callonce]

template<class Callable, class... Args> void call_once(once_flag& flag, Callable&& func, Args&&... args);
Mandates: is_­invocable_­v<Callable, Args...> is true.
Effects: An execution of call_­once that does not call its func is a passive execution.
An execution of call_­once that calls its func is an active execution.
An active execution calls INVOKE(​std​::​forward<Callable>(func), std​::​forward<Args>(args)...).
If such a call to func throws an exception the execution is exceptional, otherwise it is returning.
An exceptional execution propagates the exception to the caller of call_­once.
Among all executions of call_­once for any given 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.
[Note 1:
Passive executions allow other threads to reliably observe the results produced by the earlier returning execution.
โ€” end note]
Synchronization: For any given once_­flag: all active executions occur in a total order; completion of an active execution synchronizes with the start of the next one in this total order; and the returning execution synchronizes with the return from all passive executions.
Throws: system_­error when an exception is required ([thread.req.exception]), or any exception thrown by func.
[Example 1: // 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 example]

32.6 Condition variables [thread.condition]

32.6.1 General [thread.condition.general]

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 condition_­variable provides a condition variable that can only wait on an object of type unique_­lock<mutex>, allowing the implementation to be more efficient.
Class condition_­variable_­any provides a general condition variable that can wait on objects of user-supplied lock types.
Condition variables permit concurrent invocation of the wait, wait_­for, wait_­until, notify_­one and notify_­all member functions.
The executions of notify_­one and notify_­all are atomic.
The executions of wait, wait_­for, and wait_­until are performed in three atomic parts:
1.the release of the mutex and entry into the waiting state;
2.the unblocking of the wait; and
3.the reacquisition of the lock.
The implementation behaves as if all executions of notify_­one, notify_­all, and each part of the wait, wait_­for, and wait_­until executions are executed in a single unspecified total order consistent with the "happens before" order.
Condition variable construction and destruction need not be synchronized.

32.6.2 Header <condition_­variable> synopsis [condition.variable.syn]

namespace std { class condition_variable; class condition_variable_any; void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); enum class cv_status { no_timeout, timeout }; }

32.6.3 Non-member functions [thread.condition.nonmember]

void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
Preconditions: lk is locked by the calling thread and either
  • no other thread is waiting on cond, or
  • lk.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_­for, or wait_­until) threads.
Effects: Transfers ownership of the lock associated with lk into internal storage and schedules 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: lk.unlock(); cond.notify_all();
Synchronization: The implied lk.unlock() call is sequenced after the destruction of all objects with thread storage duration associated with the current thread.
[Note 1:
The supplied lock is held until the thread exits, which might cause deadlock due to lock ordering issues.
โ€” end note]
[Note 2:
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 lk, and that this lock is not released and reacquired prior to calling notify_­all_­at_­thread_­exit.
โ€” end note]

32.6.4 Class condition_­variable [thread.condition.condvar]

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<mutex>& lock); template<class Predicate> void wait(unique_lock<mutex>& lock, Predicate pred); template<class Clock, class Duration> cv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time); template<class Clock, class Duration, class Predicate> bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template<class Rep, class Period> cv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time); template<class Rep, class Period, class Predicate> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); using native_handle_type = implementation-defined; // see [thread.req.native] native_handle_type native_handle(); // see [thread.req.native] }; }
The class condition_­variable is a standard-layout class ([class.prop]).
condition_variable();
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • resource_­unavailable_­try_­again โ€” if some non-memory resource limitation prevents initialization.
~condition_variable();
Preconditions: There is no thread blocked on *this.
[Note 1:
That is, all threads have been notified; they could 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 *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 wait, wait_­for, or wait_­until that take a predicate.
โ€” end note]
void notify_one() noexcept;
Effects: If any threads are blocked waiting for *this, unblocks one of those threads.
void notify_all() noexcept;
Effects: Unblocks all threads that are blocked waiting for *this.
void wait(unique_lock<mutex>& lock);
Preconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread, and either
  • no other thread is waiting on this condition_­variable object or
  • lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_­for, or wait_­until) threads.
Effects:
  • Atomically calls lock.unlock() and blocks on *this.
  • When unblocked, calls lock.lock() (possibly blocking on the lock), then returns.
  • The function will unblock when signaled by a call to notify_­one() or a call to notify_­all(), or spuriously.
Postconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread.
Throws: Nothing.
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 2:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Predicate> void wait(unique_lock<mutex>& lock, Predicate pred);
Preconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread, and either
  • no other thread is waiting on this condition_­variable object or
  • lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_­for, or wait_­until) threads.
Effects: Equivalent to: while (!pred()) wait(lock);
Postconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread.
Throws: Any exception thrown by pred.
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 3:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Clock, class Duration> cv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time);
Preconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread, and either
  • no other thread is waiting on this condition_­variable object or
  • lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_­for, or wait_­until) threads.
Effects:
  • Atomically calls lock.unlock() and blocks on *this.
  • When unblocked, calls lock.lock() (possibly blocking on the lock), then returns.
  • The function will unblock when signaled by a call to notify_­one(), a call to notify_­all(), expiration of the absolute timeout ([thread.req.timing]) specified by abs_­time, or spuriously.
  • If the function exits via an exception, lock.lock() is called prior to exiting the function.
Postconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread.
Returns: cv_­status​::​timeout if the absolute timeout ([thread.req.timing]) specified by abs_­time expired, otherwise cv_­status​::​no_­timeout.
Throws: Timeout-related exceptions ([thread.req.timing]).
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 4:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Rep, class Period> cv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time);
Preconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread, and either
  • no other thread is waiting on this condition_­variable object or
  • lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_­for, or wait_­until) threads.
Effects: Equivalent to: return wait_until(lock, chrono::steady_clock::now() + rel_time);
Postconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread.
Returns: cv_­status​::​timeout if the relative timeout ([thread.req.timing]) specified by rel_­time expired, otherwise cv_­status​::​no_­timeout.
Throws: Timeout-related exceptions ([thread.req.timing]).
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 5:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Clock, class Duration, class Predicate> bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
Preconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread, and either
  • no other thread is waiting on this condition_­variable object or
  • lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_­for, or wait_­until) threads.
Effects: Equivalent to: while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;
Postconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread.
[Note 6:
The returned value indicates whether the predicate evaluated to true regardless of whether the timeout was triggered.
โ€” end note]
Throws: Timeout-related exceptions ([thread.req.timing]) or any exception thrown by pred.
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 7:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Rep, class Period, class Predicate> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
Preconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread, and either
  • no other thread is waiting on this condition_­variable object or
  • lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_­for, or wait_­until) threads.
Effects: Equivalent to: return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
[Note 8:
There is no blocking if pred() is initially true, even if the timeout has already expired.
โ€” end note]
Postconditions: lock.owns_­lock() is true and lock.mutex() is locked by the calling thread.
[Note 9:
The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered.
โ€” end note]
Throws: Timeout-related exceptions ([thread.req.timing]) or any exception thrown by pred.
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 10:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]

32.6.5 Class condition_­variable_­any [thread.condition.condvarany]

32.6.5.1 General [thread.condition.condvarany.general]

A Lock type shall meet the Cpp17BasicLockable requirements ([thread.req.lockable.basic]).
[Note 1:
All of the standard mutex types meet this requirement.
If a Lock type other than one of the standard mutex types or a unique_­lock wrapper for a standard mutex type is used with condition_­variable_­any, any necessary synchronization is assumed to be in place with respect to the predicate associated with the condition_­variable_­any instance.
โ€” end note]
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; // [thread.condvarany.wait], noninterruptible waits template<class Lock> void wait(Lock& lock); template<class Lock, class Predicate> void wait(Lock& lock, Predicate pred); template<class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time); template<class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template<class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time); template<class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred); // [thread.condvarany.intwait], interruptible waits template<class Lock, class Predicate> bool wait(Lock& lock, stop_token stoken, Predicate pred); template<class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, stop_token stoken, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred); template<class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, stop_token stoken, const chrono::duration<Rep, Period>& rel_time, Predicate pred); }; }
condition_variable_any();
Throws: bad_­alloc or system_­error when an exception is required ([thread.req.exception]).
Error conditions:
  • resource_­unavailable_­try_­again โ€” if some non-memory resource limitation prevents initialization.
  • operation_­not_­permitted โ€” if the thread does not have the privilege to perform the operation.
~condition_variable_any();
Preconditions: There is no thread blocked on *this.
[Note 2:
That is, all threads have been notified; they could 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 *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 wait, wait_­for, or wait_­until that take a predicate.
โ€” end note]
void notify_one() noexcept;
Effects: If any threads are blocked waiting for *this, unblocks one of those threads.
void notify_all() noexcept;
Effects: Unblocks all threads that are blocked waiting for *this.

32.6.5.2 Noninterruptible waits [thread.condvarany.wait]

template<class Lock> void wait(Lock& lock);
Effects:
  • Atomically calls lock.unlock() and blocks on *this.
  • When unblocked, calls lock.lock() (possibly blocking on the lock) and returns.
  • The function will unblock when signaled by a call to notify_­one(), a call to notify_­all(), or spuriously.
Postconditions: lock is locked by the calling thread.
Throws: Nothing.
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 1:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Lock, class Predicate> void wait(Lock& lock, Predicate pred);
Effects: Equivalent to: while (!pred()) wait(lock);
template<class Lock, class Clock, class Duration> cv_status wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);
Effects:
  • Atomically calls lock.unlock() and blocks on *this.
  • When unblocked, calls lock.lock() (possibly blocking on the lock) and returns.
  • The function will unblock when signaled by a call to notify_­one(), a call to notify_­all(), expiration of the absolute timeout ([thread.req.timing]) specified by abs_­time, or spuriously.
  • If the function exits via an exception, lock.lock() is called prior to exiting the function.
Postconditions: lock is locked by the calling thread.
Returns: cv_­status​::​timeout if the absolute timeout ([thread.req.timing]) specified by abs_­time expired, otherwise cv_­status​::​no_­timeout.
Throws: Timeout-related exceptions ([thread.req.timing]).
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 2:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Lock, class Rep, class Period> cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
Effects: Equivalent to: return wait_until(lock, chrono::steady_clock::now() + rel_time);
Postconditions: lock is locked by the calling thread.
Returns: cv_­status​::​timeout if the relative timeout ([thread.req.timing]) specified by rel_­time expired, otherwise cv_­status​::​no_­timeout.
Throws: Timeout-related exceptions ([thread.req.timing]).
Remarks: If the function fails to meet the postcondition, terminate() is called ([except.terminate]).
[Note 3:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
Effects: Equivalent to: while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;
[Note 4:
There is no blocking if pred() is initially true, or if the timeout has already expired.
โ€” end note]
[Note 5:
The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered.
โ€” end note]
template<class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
Effects: Equivalent to: return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));

32.6.5.3 Interruptible waits [thread.condvarany.intwait]

The following wait functions will be notified when there is a stop request on the passed stop_­token.
In that case the functions return immediately, returning false if the predicate evaluates to false.
template<class Lock, class Predicate> bool wait(Lock& lock, stop_token stoken, Predicate pred);
Effects: Registers for the duration of this call *this to get notified on a stop request on stoken during this call and then equivalent to: while (!stoken.stop_requested()) { if (pred()) return true; wait(lock); } return pred();
[Note 1:
The returned value indicates whether the predicate evaluated to true regardless of whether there was a stop request.
โ€” end note]
Postconditions: lock is locked by the calling thread.
Throws: Any exception thrown by pred.
Remarks: If the function fails to meet the postcondition, terminate is called ([except.terminate]).
[Note 2:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, stop_token stoken, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
Effects: Registers for the duration of this call *this to get notified on a stop request on stoken during this call and then equivalent to: while (!stoken.stop_requested()) { if (pred()) return true; if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); } return pred();
[Note 3:
There is no blocking if pred() is initially true, stoken.stop_­requested() was already true or the timeout has already expired.
โ€” end note]
[Note 4:
The returned value indicates whether the predicate evaluated to true regardless of whether the timeout was triggered or a stop request was made.
โ€” end note]
Postconditions: lock is locked by the calling thread.
Throws: Timeout-related exceptions ([thread.req.timing]), or any exception thrown by pred.
Remarks: If the function fails to meet the postcondition, terminate is called ([except.terminate]).
[Note 5:
This can happen if the re-locking of the mutex throws an exception.
โ€” end note]
template<class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, stop_token stoken, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
Effects: Equivalent to: return wait_until(lock, std::move(stoken), chrono::steady_clock::now() + rel_time, std::move(pred));

32.7 Semaphore [thread.sema]

32.7.1 General [thread.sema.general]

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.
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.

32.7.2 Header <semaphore> synopsis [semaphore.syn]

namespace std { template<ptrdiff_t least_max_value = implementation-defined> class counting_semaphore; using binary_semaphore = counting_semaphore<1>; }

32.7.3 Class template counting_­semaphore [thread.sema.cnt]

namespace std { template<ptrdiff_t least_max_value = implementation-defined> 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<class Rep, class Period> bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration> bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time); private: ptrdiff_t counter; // exposition only }; }
Class template 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.
least_­max_­value shall be non-negative; otherwise the program is ill-formed.
Concurrent invocations of the member functions of counting_­semaphore, other than its destructor, do not introduce data races.
static constexpr ptrdiff_t max() noexcept;
Returns: The maximum value of counter.
This value is greater than or equal to least_­max_­value.
constexpr explicit counting_semaphore(ptrdiff_t desired);
Preconditions: desired >= 0 is true, and desired <= max() is true.
Effects: Initializes counter with desired.
Throws: Nothing.
void release(ptrdiff_t update = 1);
Preconditions: update >= 0 is true, and update <= max() - counter is true.
Effects: Atomically execute counter += update.
Then, unblocks any threads that are waiting for counter to be greater than zero.
Synchronization: Strongly happens before invocations of try_­acquire that observe the result of the effects.
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions: Any of the error conditions allowed for mutex types ([thread.mutex.requirements.mutex]).
bool try_acquire() noexcept;
Effects: Attempts to atomically decrement counter if it is positive, without blocking.
If counter is not decremented, there is no effect and try_­acquire immediately returns.
An implementation may fail to decrement counter even if it is positive.
[Note 1:
This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange ([atomics]).
โ€” end note]
An implementation should ensure that try_­acquire does not consistently return false in the absence of contending semaphore operations.
Returns: true if counter was decremented, otherwise false.
void acquire();
Effects: Repeatedly performs the following steps, in order:
  • Evaluates try_­acquire.
    If the result is true, returns.
  • Blocks on *this until counter is greater than zero.
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions: Any of the error conditions allowed for mutex types ([thread.mutex.requirements.mutex]).
template<class Rep, class Period> bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time); template<class Clock, class Duration> bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);
Effects: Repeatedly performs the following steps, in order:
  • Evaluates try_­acquire().
    If the result is true, returns true.
  • Blocks on *this until counter is greater than zero or until the timeout expires.
    If it is unblocked by the timeout expiring, returns false.
The timeout expires ([thread.req.timing]) when the current time is after abs_­time (for try_­acquire_­until) or when at least rel_­time has passed from the start of the function (for try_­acquire_­for).
Throws: Timeout-related exceptions ([thread.req.timing]), or system_­error when a non-timeout-related exception is required ([thread.req.exception]).
Error conditions: Any of the error conditions allowed for mutex types ([thread.mutex.requirements.mutex]).

32.8 Coordination types [thread.coord]

32.8.1 General [thread.coord.general]

Subclause [thread.coord] describes various concepts related to thread coordination, and defines the coordination types latch and barrier.
These types facilitate concurrent computation performed by a number of threads.

32.8.2 Latches [thread.latch]

32.8.2.1 General [thread.latch.general]

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 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.

32.8.2.2 Header <latch> synopsis [latch.syn]

namespace std { class latch; }

32.8.2.3 Class latch [thread.latch.class]

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; // exposition only }; }
A 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.
Concurrent invocations of the member functions of latch, other than its destructor, do not introduce data races.
static constexpr ptrdiff_t max() noexcept;
Returns: The maximum value of counter that the implementation supports.
constexpr explicit latch(ptrdiff_t expected);
Preconditions: expected >= 0 is true and expected <= max() is true.
Effects: Initializes counter with expected.
Throws: Nothing.
void count_down(ptrdiff_t update = 1);
Preconditions: update >= 0 is true, and update <= counter is true.
Effects: Atomically decrements counter by update.
If counter is equal to zero, unblocks all threads blocked on *this.
Synchronization: Strongly happens before the returns from all calls that are unblocked.
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions: Any of the error conditions allowed for mutex types ([thread.mutex.requirements.mutex]).
bool try_wait() const noexcept;
Returns: With very low probability false.
Otherwise counter == 0.
void wait() const;
Effects: If counter equals zero, returns immediately.
Otherwise, blocks on *this until a call to count_­down that decrements counter to zero.
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions: Any of the error conditions allowed for mutex types ([thread.mutex.requirements.mutex]).
void arrive_and_wait(ptrdiff_t update = 1);
Effects: Equivalent to: count_down(update); wait();

32.8.3 Barriers [thread.barrier]

32.8.3.1 General [thread.barrier.general]

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.
[Note 1:
A barrier is useful for managing repeated tasks that are handled by multiple threads.
โ€” end note]

32.8.3.2 Header <barrier> synopsis [barrier.syn]

namespace std { template<class CompletionFunction = see below> class barrier; }

32.8.3.3 Class template barrier [thread.barrier.class]

namespace std { template<class CompletionFunction = see below> class barrier { public: using arrival_token = see below; 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; // exposition only }; }
Each barrier phase consists of the following steps:
  • The expected count is decremented by each call to arrive or arrive_­and_­drop.
  • When the expected count reaches zero, the phase completion step is run.
    For the specialization with the default value of the CompletionFunction template parameter, the completion step is run as part of the call to arrive or arrive_­and_­drop that caused the expected count to reach zero.
    For other specializations, the completion step is run on one of the threads that arrived at the barrier during the phase.
  • When the completion step finishes, the expected count is reset to what was specified by the expected argument to the constructor, possibly adjusted by calls to arrive_­and_­drop, and the next phase starts.
Each phase defines a phase synchronization point.
Threads that arrive at the barrier during the phase can block on the phase synchronization point by calling wait, and will remain blocked until the phase completion step is run.
The phase completion step that is executed at the end of each phase has the following effects:
  • Invokes the completion function, equivalent to completion().
  • Unblocks all threads that are blocked on the phase synchronization point.
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 CompletionFunction template parameter, the behavior is undefined if any of the barrier object's member functions other than wait are called while the completion step is in progress.
Concurrent invocations of the member functions of barrier, other than its destructor, do not introduce data races.
The member functions arrive and arrive_­and_­drop execute atomically.
CompletionFunction shall meet the Cpp17MoveConstructible (Table 28) and Cpp17Destructible (Table 32) requirements.
is_­nothrow_­invocable_­v<CompletionFunction&> shall be true.
The default value of the CompletionFunction template parameter is an unspecified type, such that, in addition to satisfying the requirements of CompletionFunction, it meets the Cpp17DefaultConstructible requirements (Table 27) and completion() has no effects.
barrier​::​arrival_­token is an unspecified type, such that it meets the Cpp17MoveConstructible (Table 28), Cpp17MoveAssignable (Table 30), and Cpp17Destructible (Table 32) requirements.
static constexpr ptrdiff_t max() noexcept;
Returns: The maximum expected count that the implementation supports.
constexpr explicit barrier(ptrdiff_t expected, CompletionFunction f = CompletionFunction());
Preconditions: expected >= 0 is true and expected <= max() is true.
Effects: Sets both the initial expected count for each barrier phase and the current expected count for the first phase to expected.
Initializes completion with std​::​move(f).
Starts the first phase.
[Note 1:
If expected is 0 this object can only be destroyed.
โ€” end note]
Throws: Any exception thrown by CompletionFunction's move constructor.
[[nodiscard]] arrival_token arrive(ptrdiff_t update = 1);
Preconditions: update > 0 is true, and update is less than or equal to the expected count for the current barrier phase.
Effects: Constructs an object of type arrival_­token that is associated with the phase synchronization point for the current phase.
Then, decrements the expected count by update.
Synchronization: The call to arrive strongly happens before the start of the phase completion step for the current phase.
Returns: The constructed arrival_­token object.
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions: Any of the error conditions allowed for mutex types ([thread.mutex.requirements.mutex]).
[Note 2:
This call can cause the completion step for the current phase to start.
โ€” end note]
void wait(arrival_token&& arrival) const;
Preconditions: arrival is associated with the phase synchronization point for the current phase or the immediately preceding phase of the same barrier object.
Effects: Blocks at the synchronization point associated with std​::​move(arrival) until the phase completion step of the synchronization point's phase is run.
[Note 3:
If arrival is associated with the synchronization point for a previous phase, the call returns immediately.
โ€” end note]
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions: Any of the error conditions allowed for mutex types ([thread.mutex.requirements.mutex]).
void arrive_and_wait();
Effects: Equivalent to: wait(arrive()).
void arrive_and_drop();
Preconditions: The expected count for the current barrier phase is greater than zero.
Effects: Decrements the initial expected count for all subsequent phases by one.
Then decrements the expected count for the current phase by one.
Synchronization: The call to arrive_­and_­drop strongly happens before the start of the phase completion step for the current phase.
Throws: system_­error when an exception is required ([thread.req.exception]).
Error conditions: Any of the error conditions allowed for mutex types ([thread.mutex.requirements.mutex]).
[Note 4:
This call can cause the completion step for the current phase to start.
โ€” end note]

32.9 Futures [futures]

32.9.1 Overview [futures.overview]

[futures] describes components that a C++ 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.
[Note 1:
These components are not restricted to multi-threaded programs but can be useful in single-threaded programs as well.
โ€” end note]

32.9.2 Header <future> synopsis [future.syn]

namespace std { enum class future_errc { broken_promise = implementation-defined, future_already_retrieved = implementation-defined, promise_already_satisfied = implementation-defined, no_state = implementation-defined }; enum class launch : unspecified { async = unspecified, deferred = unspecified, implementation-defined }; enum class future_status { ready, timeout, deferred }; template<> struct is_error_code_enum<future_errc> : 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; class future_error; template<class R> class promise; template<class R> class promise<R&>; template<> class promise<void>; template<class R> void swap(promise<R>& x, promise<R>& y) noexcept; template<class R, class Alloc> struct uses_allocator<promise<R>, Alloc>; template<class R> class future; template<class R> class future<R&>; template<> class future<void>; template<class R> class shared_future; template<class R> class shared_future<R&>; template<> class shared_future<void>; template<class> class packaged_task; // not defined template<class R, class... ArgTypes> class packaged_task<R(ArgTypes...)>; template<class R, class... ArgTypes> void swap(packaged_task<R(ArgTypes...)>&, packaged_task<R(ArgTypes...)>&) noexcept; template<class F, class... Args> [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(F&& f, Args&&... args); template<class F, class... Args> [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(launch policy, F&& f, Args&&... args); }
The enum type launch is a bitmask type with elements launch​::​async and launch​::​deferred.
[Note 1:
Implementations can provide bitmasks to specify restrictions on task interaction by functions launched by async() applicable to a corresponding subset of available launch policies.
Implementations can extend the behavior of the first overload of async() by adding their extensions to the launch policy under the โ€œas ifโ€ rule.
โ€” end note]
The enum values of future_­errc are distinct and not zero.

32.9.3 Error handling [futures.errors]

const error_category& future_category() noexcept;
Returns: A reference to an object of a type derived from class error_­category.
The object's default_­error_­condition and equivalent virtual functions shall behave as specified for the class error_­category.
The object's name virtual function returns a pointer to the string "future".
error_code make_error_code(future_errc e) noexcept;
Returns: error_­code(static_­cast<int>(e), future_­category()).
error_condition make_error_condition(future_errc e) noexcept;
Returns: error_­condition(static_­cast<int>(e), future_­category()).

32.9.4 Class future_­error [futures.future.error]

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_; // exposition only }; }
explicit future_error(future_errc e);
Effects: Initializes ec_­ with make_­error_­code(e).
const error_code& code() const noexcept;
Returns: ec_­.
const char* what() const noexcept;
Returns: An ntbs incorporating code().message().

32.9.5 Shared state [futures.state]

Many of the classes introduced in subclause [futures] use some state to communicate results.
This shared state consists of some state information and some (possibly not yet evaluated) result, which can be a (possibly void) value or an exception.
[Note 1:
Futures, promises, and tasks defined in this Clause reference such shared state.
โ€” end note]
[Note 2:
The result can be any kind of object including a function to compute that result, as used by async when policy is launch​::​deferred.
โ€” end note]
An asynchronous return object is an object that reads results from a shared state.
A 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 ([thread.req.lockable]), then it is a timed waiting function, otherwise it is a non-timed waiting function.
An 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.
[Note 3:
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.
When an asynchronous return object or an asynchronous provider is said to release its shared state, it means:
  • if the return object or provider holds the last reference to its shared state, the shared state is destroyed; and
  • the return object or provider gives up its reference to its shared state; and
  • 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 std​::​async, the shared state is not yet ready, and this was the last reference to the shared state.
When an asynchronous provider is said to make its shared state ready, it means:
  • first, the provider marks its shared state as ready; and
  • second, the provider unblocks any execution agents waiting for its shared state to become ready.
When an asynchronous provider is said to abandon its shared state, it means:
  • first, if that state is not ready, the provider
    • stores an exception object of type future_­error with an error condition of broken_­promise within its shared state; and then
    • makes its shared state ready;
  • second, the provider releases its shared state.
A shared state is 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.
Calls to functions that successfully set the stored result of a shared state synchronize with 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 the successful return from a call to a waiting function on the shared state.
Some functions (e.g., 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 is sequenced before making that shared state ready.
Access to the result of the same shared state may conflict.
[Note 4:
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 ([res.on.data.races]).
For example, concurrent accesses through references returned by shared_­future​::​get() ([futures.shared.future]) must either use read-only operations or provide additional synchronization.
โ€” end note]

32.9.6 Class template promise [futures.promise]

namespace std { template<class R> class promise { public: promise(); template<class Allocator> 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<R> get_future(); // setting the result void set_value(see below); void set_exception(exception_ptr p); // setting the result with deferred notification void set_value_at_thread_exit(see below); void set_exception_at_thread_exit(exception_ptr p); }; template<class R> void swap(promise<R>& x, promise<R>& y) noexcept; template<class R, class Alloc> struct uses_allocator<promise<R>, Alloc>; }
The implementation provides the template promise and two specializations, promise<R&> and promise<void>.
These differ only in the argument type of the member functions set_­value and set_­value_­at_­thread_­exit, as set out in their descriptions, below.
The set_­value, set_­exception, set_­value_­at_­thread_­exit, and 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.
template<class R, class Alloc> struct uses_allocator<promise<R>, Alloc> : true_type { };
Preconditions: Alloc meets the Cpp17Allocator requirements (Table 36).
promise(); template<class Allocator> promise(allocator_arg_t, const Allocator& a);
Effects: Creates a shared state.
The second constructor uses the allocator a to allocate memory for the shared state.
promise(promise&& rhs) noexcept;
Effects: Transfers ownership of the shared state of rhs (if any) to the newly-constructed object.
Postconditions: rhs has no shared state.
~promise();
Effects: Abandons any shared state ([futures.state]).
promise& operator=(promise&& rhs) noexcept;
Effects: Abandons any shared state ([futures.state]) and then as if promise(std​::​move(rhs)).swap(*this).
Returns: *this.
void swap(promise& other) noexcept;
Effects: Exchanges the shared state of *this and other.
Postconditions: *this has the shared state (if any) that other had prior to the call to swap.
other has the shared state (if any) that *this had prior to the call to swap.
future<R> get_future();
Returns: A future<R> object with the same shared state as *this.
Synchronization: Calls to this function do not introduce data races ([intro.multithread]) with calls to set_­value, set_­exception, set_­value_­at_­thread_­exit, or set_­exception_­at_­thread_­exit.
[Note 1:
Such calls need not synchronize with each other.
โ€” end note]
Throws: future_­error if *this has no shared state or if get_­future has already been called on a promise with the same shared state as *this.
Error conditions:
  • future_­already_­retrieved if get_­future has already been called on a promise with the same shared state as *this.
  • no_­state if *this has no shared state.
void promise::set_value(const R& r); void promise::set_value(R&& r); void promise<R&>::set_value(R& r); void promise<void>::set_value();
Effects: Atomically stores the value r in the shared state and makes that state ready ([futures.state]).
Throws:
  • future_­error if its shared state already has a stored value or exception, or
  • for the first version, any exception thrown by the constructor selected to copy an object of R, or
  • for the second version, any exception thrown by the constructor selected to move an object of R.
Error conditions:
  • promise_­already_­satisfied if its shared state already has a stored value or exception.
  • no_­state if *this has no shared state.
void set_exception(exception_ptr p);
Preconditions: p is not null.
Effects: Atomically stores the exception pointer p in the shared state and makes that state ready ([futures.state]).
Throws: future_­error if its shared state already has a stored value or exception.
Error conditions:
  • promise_­already_­satisfied if its shared state already has a stored value or exception.
  • no_­state if *this has no shared state.
void promise::set_value_at_thread_exit(const R& r); void promise::set_value_at_thread_exit(R&& r); void promise<R&>::set_value_at_thread_exit(R& r); void promise<void>::set_value_at_thread_exit();
Effects: Stores the value 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.
Throws:
  • future_­error if its shared state already has a stored value or exception, or
  • for the first version, any exception thrown by the constructor selected to copy an object of R, or
  • for the second version, any exception thrown by the constructor selected to move an object of R.
Error conditions:
  • promise_­already_­satisfied if its shared state already has a stored value or exception.
  • no_­state if *this has no shared state.
void set_exception_at_thread_exit(exception_ptr p);
Preconditions: p is not null.
Effects: Stores the exception pointer 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.
Throws: future_­error if an error condition occurs.
Error conditions:
  • promise_­already_­satisfied if its shared state already has a stored value or exception.
  • no_­state if *this has no shared state.
template<class R> void swap(promise<R>& x, promise<R>& y) noexcept;
Effects: As if by x.swap(y).

32.9.7 Class template future [futures.unique.future]

The class template future defines a type for asynchronous return objects which do not share their shared state with other asynchronous return objects.
A default-constructed future object has no shared state.
A future object with shared state can be created by functions on asynchronous providers or by the move constructor and shares its shared state with the original asynchronous provider.
The result (value or exception) of a future object can be set by calling a respective function on an object that shares the same shared state.
[Note 1:
Member functions of future do not synchronize with themselves or with member functions of shared_­future.
โ€” end note]
The effect of calling any member function other than the destructor, the move-assignment operator, share, or valid on a future object for which valid() == false is undefined.
[Note 2:
It is valid to move from a future object for which valid() == false.
โ€” end note]
Recommended practice: Implementations should detect this case and throw an object of type future_­error with an error condition of future_­errc​::​no_­state.
namespace std { template<class R> class future { public: future() noexcept; future(future&&) noexcept; future(const future&) = delete; ~future(); future& operator=(const future&) = delete; future& operator=(future&&) noexcept; shared_future<R> share() noexcept; // retrieving the value see below get(); // functions to check state bool valid() const noexcept; void wait() const; template<class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const; template<class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const; }; }
The implementation provides the template future and two specializations, future<R&> and future<void>.
These differ only in the return type and return value of the member function get, as set out in its description, below.
future() noexcept;
Effects: The object does not refer to a shared state.
Postconditions: valid() == false.
future(future&& rhs) noexcept;
Effects: Move constructs a future object that refers to the shared state that was originally referred to by rhs (if any).
Postconditions:
  • valid() returns the same value as rhs.valid() prior to the constructor invocation.
  • rhs.valid() == false.
~future();
Effects:
future& operator=(future&& rhs) noexcept;
Effects:
Postconditions:
  • valid() returns the same value as rhs.valid() prior to the assignment.
  • rhs.valid() == false.
shared_future<R> share() noexcept;
Postconditions: valid() == false.
Returns: shared_­future<R>(std​::​move(*this)).
R future::get(); R& future<R&>::get(); void future<void>::get();
[Note 3:
As described above, the template and its two required specializations differ only in the return type and return value of the member function get.
โ€” end note]
Effects:
  • wait()s until the shared state is ready, then retrieves the value stored in the shared state;
  • releases any shared state ([futures.state]).
Postconditions: valid() == false.
Returns:
  • future​::​get() returns the value v stored in the object's shared state as std​::​move(v).
  • future<R&>​::​get() returns the reference stored as value in the object's shared state.
  • future<void>​::​get() returns nothing.
Throws: The stored exception, if an exception was stored in the shared state.
bool valid() const noexcept;
Returns: true only if *this refers to a shared state.
void wait() const;
Effects: Blocks until the shared state is ready.
template<class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
Effects: None if the shared state contains a deferred function ([futures.async]), otherwise blocks until the shared state is ready or until the relative timeout ([thread.req.timing]) specified by rel_­time has expired.
Returns:
  • future_­status​::​deferred if the shared state contains a deferred function.
  • future_­status​::​ready if the shared state is ready.
  • future_­status​::​timeout if the function is returning because the relative timeout ([thread.req.timing]) specified by rel_­time has expired.
Throws: timeout-related exceptions ([thread.req.timing]).
template<class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
Effects: None if the shared state contains a deferred function ([futures.async]), otherwise blocks until the shared state is ready or until the absolute timeout ([thread.req.timing]) specified by abs_­time has expired.
Returns:
  • future_­status​::​deferred if the shared state contains a deferred function.
  • future_­status​::​ready if the shared state is ready.
  • future_­status​::​timeout if the function is returning because the absolute timeout ([thread.req.timing]) specified by abs_­time has expired.
Throws: timeout-related exceptions ([thread.req.timing]).

32.9.8 Class template shared_­future [futures.shared.future]

The class template shared_­future defines a type for asynchronous return objects which may share their shared state with other asynchronous return objects.
A default-constructed shared_­future object has no shared state.
A shared_­future object with shared state can be created by conversion from a future object and shares its shared state with the original asynchronous provider of the shared state.
The result (value or exception) of a shared_­future object can be set by calling a respective function on an object that shares the same shared state.
[Note 1:
Member functions of shared_­future do not synchronize with themselves, but they synchronize with the shared state.
โ€” end note]
The effect of calling any member function other than the destructor, the move-assignment operator, the copy-assignment operator, or valid() on a shared_­future object for which valid() == false is undefined.
[Note 2:
It is valid to copy or move from a shared_­future object for which valid() is false.
โ€” end note]
Recommended practice: Implementations should detect this case and throw an object of type future_­error with an error condition of future_­errc​::​no_­state.
namespace std { template<class R> class shared_future { public: shared_future() noexcept; shared_future(const shared_future& rhs) noexcept; shared_future(future<R>&&) 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 see below get() const; // functions to check state bool valid() const noexcept; void wait() const; template<class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const; template<class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const; }; }
The implementation provides the template shared_­future and two specializations, shared_­future<R&> and shared_­future<void>.
These differ only in the return type and return value of the member function get, as set out in its description, below.
shared_future() noexcept;
Effects: The object does not refer to a shared state.
Postconditions: valid() == false.
shared_future(const shared_future& rhs) noexcept;
Effects: The object refers to the same shared state as rhs (if any).
Postconditions: valid() returns the same value as rhs.valid().
shared_future(future<R>&& rhs) noexcept; shared_future(shared_future&& rhs) noexcept;
Effects: Move constructs a shared_­future object that refers to the shared state that was originally referred to by rhs (if any).
Postconditions:
  • valid() returns the same value as rhs.valid() returned prior to the constructor invocation.
  • rhs.valid() == false.
~shared_future();
Effects:
shared_future& operator=(shared_future&& rhs) noexcept;
Effects:
Postconditions:
  • valid() returns the same value as rhs.valid() returned prior to the assignment.
  • rhs.valid() == false.
shared_future& operator=(const shared_future& rhs) noexcept;
Effects:
  • Releases any shared state ([futures.state]);
  • assigns the contents of rhs to *this.
    [Note 3:
    As a result, *this refers to the same shared state as rhs (if any).
    โ€” end note]
Postconditions: valid() == rhs.valid().
const R& shared_future::get() const; R& shared_future<R&>::get() const; void shared_future<void>::get() const;
[Note 4:
As described above, the template and its two required specializations differ only in the return type and return value of the member function get.
โ€” end note]
[Note 5:
Access to a value object stored in the shared state is unsynchronized, so operations on R might introduce a data race ([intro.multithread]).
โ€” end note]
Effects: wait()s until the shared state is ready, then retrieves the value stored in the shared state.
Returns:
  • shared_­future​::​get() returns a const reference to the value stored in the object's shared state.
    [Note 6:
    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 shared_­future object that returned the reference.
    โ€” end note]
  • shared_­future<R&>​::​get() returns the reference stored as value in the object's shared state.
  • shared_­future<void>​::​get() returns nothing.
Throws: The stored exception, if an exception was stored in the shared state.
bool valid() const noexcept;
Returns: true only if *this refers to a shared state.
void wait() const;
Effects: Blocks until the shared state is ready.
template<class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
Effects: None if the shared state contains a deferred function ([futures.async]), otherwise blocks until the shared state is ready or until the relative timeout ([thread.req.timing]) specified by rel_­time has expired.
Returns:
  • future_­status​::​deferred if the shared state contains a deferred function.
  • future_­status​::​ready if the shared state is ready.
  • future_­status​::​timeout if the function is returning because the relative timeout ([thread.req.timing]) specified by rel_­time has expired.
Throws: timeout-related exceptions ([thread.req.timing]).
template<class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
Effects: None if the shared state contains a deferred function ([futures.async]), otherwise blocks until the shared state is ready or until the absolute timeout ([thread.req.timing]) specified by abs_­time has expired.
Returns:
  • future_­status​::​deferred if the shared state contains a deferred function.
  • future_­status​::​ready if the shared state is ready.
  • future_­status​::​timeout if the function is returning because the absolute timeout ([thread.req.timing]) specified by abs_­time has expired.
Throws: timeout-related exceptions ([thread.req.timing]).

32.9.9 Function template async [futures.async]

The function template async provides a mechanism to launch a function potentially in a new thread and provides the result of the function in a future object with which it shares a shared state.
template<class F, class... Args> [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(F&& f, Args&&... args); template<class F, class... Args> [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(launch policy, F&& f, Args&&... args);
Mandates: The following are all true:
  • is_­constructible_­v<decay_­t<F>, F>,
  • (is_­constructible_­v<decay_­t<Args>, Args> &&...),
  • is_­move_­constructible_­v<decay_­t<F>>,
  • (is_­move_­constructible_­v<decay_­t<Args>> &&...), and
  • is_­invocable_­v<decay_­t<F>, decay_­t<Args>...>.
Preconditions: decay_­t<F> and each type in decay_­t<Args> meet the Cpp17MoveConstructible requirements.
Effects: The first function behaves the same as a call to the second function with a policy argument of launch​::​async | launch​::​deferred and the same arguments for F and Args.
The second function creates a shared state that is associated with the returned future object.
The further behavior of the second function depends on the policy argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):
  • If launch​::​async is set in policy, calls invoke(decay-copy(std​::​forward<F>(f)), decay-​copy(std​::​forward<Args>(args))...) ([func.require], [thread.thread.constr]) as if in a new thread of execution represented by a thread object with the calls to decay-copy being evaluated in the thread that called async.
    Any return value is stored as the result in the shared state.
    Any exception propagated from the execution of invoke(decay-copy(std​::​forward<F>(f)), decay-copy(std​::​forward​<Args>(args))...) is stored as the exceptional result in the shared state.
    The thread object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state.
  • If launch​::​deferred is set in policy, stores decay-copy(std​::​forward<F>(f)) and decay-​copy(std​::​forward<Args>(args))... in the shared state.
    These copies of f and args constitute a deferred function.
    Invocation of the deferred function evaluates invoke(std​::​move(g), std​::​move(xyz)) where g is the stored value of decay-copy(std​::​forward<F>(f)) and xyz is the stored copy of decay-copy(std​::​forward<Args>(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 ([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 invoke(std​::​move(g), std​::​move(xyz)) begins, the function is no longer considered deferred.
    Recommended practice: If this policy is specified together with other policies, such as when using a policy value of launch​::​async | launch​::​deferred, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.
  • 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.
Returns: An object of type future<invoke_­result_­t<decay_­t<F>, decay_­t<Args>...>> that refers to the shared state created by this call to async.
[Note 1:
If a future obtained from async is moved outside the local scope, the future's destructor can block for the shared state to become ready.
โ€” end note]
Synchronization: The invocation of async synchronizes with the invocation of f.
The completion of the function f is sequenced before the shared state is made ready.
[Note 2:
These apply regardless of the provided policy argument, and even if the corresponding future object is moved to another thread.
However, f might not be called at all, so its completion might never happen.
โ€” end note]
If the implementation chooses the launch​::​async policy,
  • a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined, or else time out ([thread.thread.member]);
  • the associated thread completion synchronizes with 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.
Throws: system_­error if policy == launch​::​async and the implementation is unable to start a new thread, or std​::​bad_­alloc if memory for the internal data structures could not be allocated.
Error conditions:
  • resource_­unavailable_­try_­again โ€” if policy == launch​::​async and the system is unable to start a new thread.
[Example 1: 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 }
[Note 3:
Line #1 might not result in concurrency because the async call uses the default policy, which might use launch​::​deferred, in which case the lambda might not be invoked until the get() call; in that case, work1 and work2 are called on the same thread and there is no concurrency.
โ€” end note]
โ€” end example]

32.9.10 Class template packaged_­task [futures.task]

32.9.10.1 General [futures.task.general]

The class template 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.
When the 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.
namespace std { template<class> class packaged_task; // not defined template<class R, class... ArgTypes> class packaged_task<R(ArgTypes...)> { public: // construction and destruction packaged_task() noexcept; template<class F> 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<R> get_future(); // execution void operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset(); }; template<class R, class... ArgTypes> void swap(packaged_task<R(ArgTypes...)>& x, packaged_task<R(ArgTypes...)>& y) noexcept; }

32.9.10.2 Member functions [futures.task.members]

packaged_task() noexcept;
Effects: The object has no shared state and no stored task.
template<class F> packaged_task(F&& f);
Constraints: remove_­cvref_­t<F> is not the same type as packaged_­task<R(ArgTypes...)>.
Mandates: is_­invocable_­r_­v<R, F&, ArgTypes...> is true.
Preconditions: Invoking a copy of f behaves the same as invoking f.
Effects: Constructs a new packaged_­task object with a shared state and initializes the object's stored task with std​::​forward<F>(f).
Throws: Any exceptions thrown by the copy or move constructor of f, or bad_­alloc if memory for the internal data structures could not be allocated.
packaged_task(packaged_task&& rhs) noexcept;
Effects: Transfers ownership of rhs's shared state to *this, leaving rhs with no shared state.
Moves the stored task from rhs to *this.
Postconditions: rhs has no shared state.
packaged_task& operator=(packaged_task&& rhs) noexcept;
Effects:
~packaged_task();
Effects: Abandons any shared state ([futures.state]).
void swap(packaged_task& other) noexcept;
Effects: Exchanges the shared states and stored tasks of *this and other.
Postconditions: *this has the same shared state and stored task (if any) as other prior to the call to swap.
other has the same shared state and stored task (if any) as *this prior to the call to swap.
bool valid() const noexcept;
Returns: true only if *this has a shared state.
future<R> get_future();
Returns: A future object that shares the same shared state as *this.
Synchronization: Calls to this function do not introduce data races ([intro.multithread]) with calls to operator() or make_­ready_­at_­thread_­exit.
[Note 1:
Such calls need not synchronize with each other.
โ€” end note]
Throws: A future_­error object if an error occurs.
Error conditions:
  • future_­already_­retrieved if get_­future has already been called on a packaged_­task object with the same shared state as *this.
  • no_­state if *this has no shared state.
void operator()(ArgTypes... args);
Effects: As if by INVOKE<R>(f, t, t, , t) ([func.require]), where f is the stored task of *this and t, t, , t are the values in args....
If the task returns normally, the return value is stored as the asynchronous result in the shared state of *this, otherwise the exception thrown by the task is stored.
The shared state of *this is made ready, and any threads blocked in a function waiting for the shared state of *this to become ready are unblocked.
Throws: A future_­error exception object if there is no shared state or the stored task has already been invoked.
Error conditions:
  • promise_­already_­satisfied if the stored task has already been invoked.
  • no_­state if *this has no shared state.
void make_ready_at_thread_exit(ArgTypes... args);
Effects: As if by INVOKE<R>(f, t, t, , t) ([func.require]), where f is the stored task and t, t, , t are the values in args....
If the task returns normally, the return value is stored as the asynchronous result in the shared state of *this, otherwise the exception thrown by the task is stored.
In either case, this is done without making that state ready ([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.
Throws: future_­error if an error condition occurs.
Error conditions:
  • promise_­already_­satisfied if the stored task has already been invoked.
  • no_­state if *this has no shared state.
void reset();
Effects: As if *this = packaged_­task(std​::​move(f)), where f is the task stored in *this.
[Note 2:
This constructs a new shared state for *this.
The old state is abandoned ([futures.state]).
โ€” end note]
Throws:
  • bad_­alloc if memory for the new shared state could not be allocated.
  • any exception thrown by the move constructor of the task stored in the shared state.
  • future_­error with an error condition of no_­state if *this has no shared state.

32.9.10.3 Globals [futures.task.nonmembers]

template<class R, class... ArgTypes> void swap(packaged_task<R(ArgTypes...)>& x, packaged_task<R(ArgTypes...)>& y) noexcept;
Effects: As if by x.swap(y).