|
|
|
33.4.3
Mutex requirements
[thread.mutex.requirements]
33.4.3.1
In general
[thread.mutex.requirements.general]
1
A mutex object facilitates protection against data races and allows safe synchronization of data between
execution agents (33.2.5). An execution agent owns a mutex from the time it successfully calls one of the lock
functions until it calls unlock. Mutexes can be either recursive or non-recursive, and can grant simultaneous
ownership to one or many execution agents. Both recursive and non-recursive mutexes are supplied.
33.4.3.2
Mutex types
[thread.mutex.requirements.mutex]
1
The mutex types are the standard library types mutex, recursive_mutex, timed_mutex, recursive_timed_-
mutex, shared_mutex, and shared_timed_mutex. They shall meet the requirements set out in this subclause.
In this description, m denotes an object of a mutex type.
2
The mutex types shall meet the Lockable requirements (33.2.5.3).
3
The mutex types shall be DefaultConstructible and Destructible. If initialization of an object of a
mutex type fails, an exception of type system_error shall be thrown. The mutex types shall not be copyable
or movable.
4
The error conditions for error codes, if any, reported by member functions of the mutex types shall be:
(4.1)
—
resource_unavailable_try_again — if any native handle type manipulated is not available.
(4.2)
—
operation_not_permitted — if the thread does not have the privilege to perform the operation.
(4.3)
—
invalid_argument — if any native handle type manipulated as part of mutex construction is incorrect.
5
The implementation shall provide lock and unlock operations, as described below. For purposes of determining
the existence of a data race, these behave as atomic operations (6.8.2). The lock and unlock operations on a
single mutex shall appear to occur in a single total order. [ Note: This can be viewed as the modification
order (6.8.2) of the mutex.
— end note ] [ Note: Construction and destruction of an object of a mutex type
need not be thread-safe; other synchronization should be used to ensure that mutex objects are initialized
and visible to other threads.
— end note ]
6
The expression m.lock() shall be well-formed and have the following semantics:
7
Requires: If m is of type mutex, timed_mutex, shared_mutex, or shared_timed_mutex, the calling
thread does not own the mutex.
8
Effects: Blocks the calling thread until ownership of the mutex can be obtained for the calling thread.
9
Postconditions: The calling thread owns the mutex.
10
Return type: void.
11
Synchronization: Prior unlock() operations on the same object shall synchronize with (6.8.2) this
operation.
12
Throws: system_error when an exception is required (33.2.2).
13
Error conditions:
(13.1)
—
operation_not_permitted — if the thread does not have the privilege to perform the operation.
(13.2)
—
resource_deadlock_would_occur — if the implementation detects that a deadlock would occur.
14
The expression m.try_lock() shall be well-formed and have the following semantics:
15
Requires: If m is of type mutex, timed_mutex, shared_mutex, or shared_timed_mutex, the calling
thread does not own the mutex.
16
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: This spurious failure is normally
uncommon, but allows interesting implementations based on a simple compare and exchange (Clause
32).
— end note ] An implementation should ensure that try_lock() does not consistently return
false in the absence of contending mutex acquisitions.
17
Return type: bool.
18
Returns: true if ownership of the mutex was obtained for the calling thread, otherwise false.
19
Synchronization: If try_lock() returns true, prior unlock() operations on the same object synchronize
with (6.8.2) this operation. [ Note: Since lock() does not synchronize with a failed subsequent try_-
§ 33.4.3.2
1222
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 ]
20
Throws: Nothing.
21
The expression m.unlock() shall be well-formed and have the following semantics:
22
Requires: The calling thread shall own the mutex.
23
Effects: Releases the calling thread’s ownership of the mutex.
24
Return type: void.
25
Synchronization: This operation synchronizes with (6.8.2) subsequent lock operations that obtain
ownership on the same object.
26
Throws: Nothing.
33.4.3.2.1
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 33.2.3
native_handle_type native_handle();
// see 33.2.3
};
}
1
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().
2
[Note: 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 ]
3
The class mutex shall satisfy all of the mutex requirements (33.4.3). It shall be a standard-layout class (Clause
12).
4
[Note: A program may 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 may be
observed.
— end note ]
5
The behavior of a program is undefined if it destroys a mutex object owned by any thread or a thread
terminates while owning a mutex object.
33.4.3.2.2
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;
§ 33.4.3.2.2
1223
void lock();
bool try_lock() noexcept;
void unlock();
using native_handle_type = implementation-defined;
// see 33.2.3
native_handle_type native_handle();
// see 33.2.3
};
}
1
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.
2
The class recursive_mutex shall satisfy all of the mutex requirements (33.4.3). It shall be a standard-layout
class (Clause 12).
3
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() shall fail, and additional calls to lock() shall 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.
4
The behavior of a program is undefined if:
(4.1)
—
it destroys a recursive_mutex object owned by any thread or
(4.2)
—
a thread terminates while owning a recursive_mutex object.
33.4.3.3
Timed mutex types
[thread.timedmutex.requirements]
1
The timed mutex types are the standard library types timed_mutex, recursive_timed_mutex, and shared_-
timed_mutex. They shall 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 (23.17.5), and abs_time denotes
an object of an instantiation of time_point (23.17.6).
2
The timed mutex types shall meet the TimedLockable requirements (33.2.5.4).
3
The expression m.try_lock_for(rel_time) shall be well-formed and have the following semantics:
4
Requires: If m is of type timed_mutex or shared_timed_mutex, the calling thread does not own the
mutex.
5
Effects: The function attempts to obtain ownership of the mutex within the relative timeout (33.2.4)
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
shall return within the timeout specified by rel_time only if it has obtained ownership of the mutex
object. [ Note: 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 ]
6
Return type: bool.
7
Returns: true if ownership was obtained, otherwise false.
8
Synchronization: If try_lock_for() returns true, prior unlock() operations on the same object
synchronize with (6.8.2) this operation.
9
Throws: Timeout-related exceptions (33.2.4).
10
The expression m.try_lock_until(abs_time) shall be well-formed and have the following semantics:
11
Requires: If m is of type timed_mutex or shared_timed_mutex, the calling thread does not own the
mutex.
12
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
shall return before the absolute timeout (33.2.4) specified by abs_time only if it has obtained ownership
of the mutex object. [ Note: 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 ]
13
Return type: bool.
§ 33.4.3.3
1224
14
Returns: true if ownership was obtained, otherwise false.
15
Synchronization: If try_lock_until() returns true, prior unlock() operations on the same object
synchronize with (6.8.2) this operation.
16
Throws: Timeout-related exceptions (33.2.4).
33.4.3.3.1
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 33.2.3
native_handle_type native_handle();
// see 33.2.3
};
}
1
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).
2
The class timed_mutex shall satisfy all of the timed mutex requirements (33.4.3.3). It shall be a standard-
layout class (Clause 12).
3
The behavior of a program is undefined if:
(3.1)
—
it destroys a timed_mutex object owned by any thread,
(3.2)
—
a thread that owns a timed_mutex object calls lock(), try_lock(), try_lock_for(), or try_lock_-
until() on that object, or
(3.3)
—
a thread terminates while owning a timed_mutex object.
33.4.3.3.2
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();
§ 33.4.3.3.2
1225
using native_handle_type = implementation-defined;
// see 33.2.3
native_handle_type native_handle();
// see 33.2.3
};
}
1
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).
2
The class recursive_timed_mutex shall satisfy all of the timed mutex requirements (33.4.3.3). It shall be a
standard-layout class (Clause 12).
3
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() shall fail, and additional calls to lock() shall 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.
4
The behavior of a program is undefined if:
(4.1)
—
it destroys a recursive_timed_mutex object owned by any thread, or
(4.2)
—
a thread terminates while owning a recursive_timed_mutex object.
33.4.3.4
Shared mutex types
[thread.sharedmutex.requirements]
1
The standard library types shared_mutex and shared_timed_mutex are shared mutex types. Shared mutex
types shall meet the requirements of mutex types (33.4.3.2), and additionally shall meet the requirements set
out below. In this description, m denotes an object of a shared mutex type.
2
In addition to the exclusive lock ownership mode specified in 33.4.3.2, 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 shall hold 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 shall be at least 10000. If more than
the maximum number of execution agents attempt to obtain a shared lock, the excess execution agents shall
block until the number of shared locks are reduced below the maximum amount by other execution agents
releasing their shared lock.
3
The expression m.lock_shared() shall be well-formed and have the following semantics:
4
Requires: The calling thread has no ownership of the mutex.
5
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 shall not have been acquired for the current thread.
6
Postconditions: The calling thread has a shared lock on the mutex.
7
Return type: void.
8
Synchronization: Prior unlock() operations on the same object shall synchronize with (6.8.2) this
operation.
9
Throws: system_error when an exception is required (33.2.2).
10
Error conditions:
(10.1)
—
operation_not_permitted — if the thread does not have the privilege to perform the operation.
(10.2)
—
resource_deadlock_would_occur — if the implementation detects that a deadlock would occur.
11
The expression m.unlock_shared() shall be well-formed and have the following semantics:
12
Requires: The calling thread shall hold a shared lock on the mutex.
13
Effects: Releases a shared lock on the mutex held by the calling thread.
14
Return type: void.
§ 33.4.3.4
1226
15
Synchronization: This operation synchronizes with (6.8.2) subsequent lock() operations that obtain
ownership on the same object.
16
Throws: Nothing.
17
The expression m.try_lock_shared() shall be well-formed and have the following semantics:
18
Requires: The calling thread has no ownership of the mutex.
19
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.
20
Return type: bool.
21
Returns: true if the shared ownership lock was acquired, false otherwise.
22
Synchronization: If try_lock_shared() returns true, prior unlock() operations on the same object
synchronize with (6.8.2) this operation.
23
Throws: Nothing.
33.4.3.4.1
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 33.2.3
native_handle_type native_handle();
// see 33.2.3
};
}
1
The class shared_mutex provides a non-recursive mutex with shared ownership semantics.
2
The class shared_mutex shall satisfy all of the shared mutex requirements (33.4.3.4). It shall be a standard-
layout class (Clause 12).
3
The behavior of a program is undefined if:
(3.1)
—
it destroys a shared_mutex object owned by any thread,
(3.2)
—
a thread attempts to recursively gain any ownership of a shared_mutex, or
(3.3)
—
a thread terminates while possessing any ownership of a shared_mutex.
4
shared_mutex may be a synonym for shared_timed_mutex.
33.4.3.5
Shared timed mutex types
[thread.sharedtimedmutex.requirements]
1
The standard library type shared_timed_mutex is a shared timed mutex type. Shared timed mutex types
shall meet the requirements of timed mutex types (33.4.3.3), shared mutex types (33.4.3.4), and additionally
shall 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 (23.17.5), and abs_time denotes an object
of an instantiation of time_point (23.17.6).
§ 33.4.3.5
1227
2
The expression m.try_lock_shared_for(rel_time) shall be well-formed and have the following semantics:
3
Requires: The calling thread has no ownership of the mutex.
4
Effects: Attempts to obtain shared lock ownership for the calling thread within the relative timeout
(33.2.4) 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 shall return within the timeout specified by rel_time only if it has
obtained shared ownership of the mutex object. [Note: 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 shall not have been
acquired for the current thread.
5
Return type: bool.
6
Returns: true if the shared lock was acquired, false otherwise.
7
Synchronization: If try_lock_shared_for() returns true, prior unlock() operations on the same
object synchronize with (6.8.2) this operation.
8
Throws: Timeout-related exceptions (33.2.4).
9
The expression m.try_lock_shared_until(abs_time) shall be well-formed and have the following semantics:
10
Requires: The calling thread has no ownership of the mutex.
11
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 shall return before the absolute timeout (33.2.4) specified by abs_time only
if it has obtained shared ownership of the mutex object.
[Note: 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 shall not have
been acquired for the current thread.
12
Return type: bool.
13
Returns: true if the shared lock was acquired, false otherwise.
14
Synchronization: If try_lock_shared_until() returns true, prior unlock() operations on the same
object synchronize with (6.8.2) this operation.
15
Throws: Timeout-related exceptions (33.2.4).
33.4.3.5.1
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);
§ 33.4.3.5.1
1228
void unlock_shared();
};
}
1
The class shared_timed_mutex provides a non-recursive mutex with shared ownership semantics.
2
The class shared_timed_mutex shall satisfy all of the shared timed mutex requirements (33.4.3.5). It shall
be a standard-layout class (Clause 12).
3
The behavior of a program is undefined if:
(3.1)
—
it destroys a shared_timed_mutex object owned by any thread,
(3.2)
—
a thread attempts to recursively gain any ownership of a shared_timed_mutex, or
(3.3)
—
a thread terminates while possessing any ownership of a shared_timed_mutex.
33.4.4
Locks
[thread.lock]
1
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: Locks are intended to ease the burden of unlocking
the lockable object under both normal and exceptional circumstances.
— end note ]
2
Some lock constructors take tag types which describe what should be done with the lockable object during
the lock’s construction.
namespace std {
struct defer_lock_t
{ };
// do not acquire ownership of the mutex
struct try_to_lock_t { };
// try to acquire ownership of the mutex
// without blocking
struct adopt_lock_t
{ };
// assume the calling thread has already
// obtained mutex ownership and manage it
inline constexpr defer_lock_t defer_lock { };
inline constexpr try_to_lock_t try_to_lock { };
inline constexpr adopt_lock_t adopt_lock { };
}
33.4.4.1
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
};
}
1
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 (6.6.3). 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 BasicLockable requirements (33.2.5.2).
explicit lock_guard(mutex_type& m);
2
Requires: If mutex_type is not a recursive mutex, the calling thread does not own the mutex m.
§ 33.4.4.1
1229
3
Effects: As if by m.lock().
4
Postconditions: &pm == &m
lock_guard(mutex_type& m, adopt_lock_t);
5
Requires: The calling thread owns the mutex m.
6
Postconditions: &pm == &m
7
Throws: Nothing.
~lock_guard();
8
Effects: As if by pm.unlock().
33.4.4.2
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
};
}
1
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 (6.6.3). 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 BasicLockable requirements (33.2.5.2). Otherwise, each of the mutex types shall meet the Lockable
requirements (33.2.5.3).
explicit scoped_lock(MutexTypes&... m);
2
Requires: If a MutexTypes type is not a recursive mutex, the calling thread does not own the corre-
sponding mutex element of m.
3
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);
4
Requires: The calling thread owns all the mutexes in m.
5
Effects: Initializes pm with tie(m...).
6
Throws: Nothing.
~scoped_lock();
7
Effects: For all i in [0, sizeof...(MutexTypes)), get<i>(pm).unlock().
33.4.4.3
Class template unique_lock
[thread.lock.unique]
namespace std {
template<class Mutex>
class unique_lock {
public:
using mutex_type = Mutex;
§ 33.4.4.3
1230
// 33.4.4.3.1, 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);
// 33.4.4.3.2, 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();
// 33.4.4.3.3, modifiers
void swap(unique_lock& u) noexcept;
mutex_type* release() noexcept;
// 33.4.4.3.4, 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;
}
1
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 (6.6.3) of the unique_lock object. The supplied
Mutex type shall meet the BasicLockable requirements (33.2.5.2).
2
[Note: unique_lock<Mutex> meets the BasicLockable requirements. If Mutex meets the Lockable re-
quirements (33.2.5.3), unique_lock<Mutex> also meets the Lockable requirements; if Mutex meets the
TimedLockable requirements (33.2.5.4), unique_lock<Mutex> also meets the TimedLockable requirements.
— end note ]
33.4.4.3.1
unique_lock constructors, destructor, and assignment
[thread.lock.unique.cons]
unique_lock() noexcept;
1
Effects: Constructs an object of type unique_lock.
2
Postconditions: pm == 0 and owns == false.
§ 33.4.4.3.1
1231
explicit unique_lock(mutex_type& m);
3
Requires: If mutex_type is not a recursive mutex the calling thread does not own the mutex.
4
Effects: Constructs an object of type unique_lock and calls m.lock().
5
Postconditions: pm == addressof(m) and owns == true.
unique_lock(mutex_type& m, defer_lock_t) noexcept;
6
Effects: Constructs an object of type unique_lock.
7
Postconditions: pm == addressof(m) and owns == false.
unique_lock(mutex_type& m, try_to_lock_t);
8
Requires: The supplied Mutex type shall meet the Lockable requirements (33.2.5.3). If mutex_type is
not a recursive mutex the calling thread does not own the mutex.
9
Effects: Constructs an object of type unique_lock and calls m.try_lock().
10
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);
11
Requires: The calling thread owns the mutex.
12
Effects: Constructs an object of type unique_lock.
13
Postconditions: pm == addressof(m) and owns == true.
14
Throws: Nothing.
template<class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
15
Requires: If mutex_type is not a recursive mutex the calling thread does not own the mutex. The
supplied Mutex type shall meet the TimedLockable requirements (33.2.5.4).
16
Effects: Constructs an object of type unique_lock and calls m.try_lock_until(abs_time).
17
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);
18
Requires: If mutex_type is not a recursive mutex the calling thread does not own the mutex. The
supplied Mutex type shall meet the TimedLockable requirements (33.2.5.4).
19
Effects: Constructs an object of type unique_lock and calls m.try_lock_for(rel_time).
20
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;
21
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);
22
Effects: If owns calls pm->unlock().
23
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.
24
[ Note: 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 ]
25
Throws: Nothing.
~unique_lock();
26
Effects: If owns calls pm->unlock().
§ 33.4.4.3.1
1232
33.4.4.3.2
unique_lock locking
[thread.lock.unique.locking]
void lock();
1
Effects: As if by pm->lock().
2
Postconditions: owns == true.
3
Throws: Any exception thrown by pm->lock(). system_error when an exception is required (33.2.2).
4
Error conditions:
(4.1)
—
operation_not_permitted — if pm is nullptr.
(4.2)
—
resource_deadlock_would_occur — if on entry owns is true.
bool try_lock();
5
Requires: The supplied Mutex shall meet the Lockable requirements (33.2.5.3).
6
Effects: As if by pm->try_lock().
7
Returns: The value returned by the call to try_lock().
8
Postconditions: owns == res, where res is the value returned by the call to try_lock().
9
Throws: Any exception thrown by pm->try_lock(). system_error when an exception is required
(33.2.2).
10
Error conditions:
(10.1)
—
operation_not_permitted — if pm is nullptr.
(10.2)
—
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);
11
Requires: The supplied Mutex type shall meet the TimedLockable requirements (33.2.5.4).
12
Effects: As if by pm->try_lock_until(abs_time).
13
Returns: The value returned by the call to try_lock_until(abs_time).
14
Postconditions: owns == res, where res is the value returned by the call to try_lock_until(abs_-
time).
15
Throws: Any exception thrown by pm->try_lock_until(). system_error when an exception is
required (33.2.2).
16
Error conditions:
(16.1)
—
operation_not_permitted — if pm is nullptr.
(16.2)
—
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);
17
Requires: The supplied Mutex type shall meet the TimedLockable requirements (33.2.5.4).
18
Effects: As if by pm->try_lock_for(rel_time).
19
Returns: The value returned by the call to try_lock_until(rel_time).
20
Postconditions: owns == res, where res is the value returned by the call to try_lock_for(rel_time).
21
Throws: Any exception thrown by pm->try_lock_for(). system_error when an exception is required
(33.2.2).
22
Error conditions:
(22.1)
—
operation_not_permitted — if pm is nullptr.
(22.2)
—
resource_deadlock_would_occur — if on entry owns is true.
void unlock();
23
Effects: As if by pm->unlock().
24
Postconditions: owns == false.
§ 33.4.4.3.2
1233
25
Throws: system_error when an exception is required (33.2.2).
26
Error conditions:
(26.1)
—
operation_not_permitted — if on entry owns is false.
33.4.4.3.3
unique_lock modifiers
[thread.lock.unique.mod]
void swap(unique_lock& u) noexcept;
1
Effects: Swaps the data members of *this and u.
mutex_type* release() noexcept;
2
Returns: The previous value of pm.
3
Postconditions: pm == 0 and owns == false.
template<class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>&
y)
noexcept;
4
Effects: As if by x.swap(y).
33.4.4.3.4
unique_lock observers
[thread.lock.unique.obs]
bool owns_lock() const noexcept;
1
Returns: owns.
explicit operator bool() const noexcept;
2
Returns: owns.
mutex_type *mutex() const noexcept;
3
Returns: pm.
33.4.4.4
Class template shared_lock
[thread.lock.shared]
namespace std {
template<class Mutex>
class shared_lock {
public:
using mutex_type = Mutex;
// 33.4.4.4.1, 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;
// 33.4.4.4.2, 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();
§
33.4.4.4
1234
// 33.4.4.4.3, modifiers
void swap(shared_lock& u) noexcept;
mutex_type* release() noexcept;
// 33.4.4.4.4, 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;
}
1
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 (6.6.3) of the shared_lock object.
The supplied Mutex type shall meet the shared mutex requirements (33.4.3.5).
2
[ Note: shared_lock<Mutex> meets the TimedLockable requirements (33.2.5.4).
— end note ]
33.4.4.4.1
shared_lock constructors, destructor, and assignment
[thread.lock.shared.cons]
shared_lock() noexcept;
1
Effects: Constructs an object of type shared_lock.
2
Postconditions: pm == nullptr and owns == false.
explicit shared_lock(mutex_type& m);
3
Requires: The calling thread does not own the mutex for any ownership mode.
4
Effects: Constructs an object of type shared_lock and calls m.lock_shared().
5
Postconditions: pm == addressof(m) and owns == true.
shared_lock(mutex_type& m, defer_lock_t) noexcept;
6
Effects: Constructs an object of type shared_lock.
7
Postconditions: pm == addressof(m) and owns == false.
shared_lock(mutex_type& m, try_to_lock_t);
8
Requires: The calling thread does not own the mutex for any ownership mode.
9
Effects: Constructs an object of type shared_lock and calls m.try_lock_shared().
10
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);
11
Requires: The calling thread has shared ownership of the mutex.
12
Effects: Constructs an object of type shared_lock.
13
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);
14
Requires: The calling thread does not own the mutex for any ownership mode.
15
Effects: Constructs an object of type shared_lock and calls m.try_lock_shared_until(abs_time).
§ 33.4.4.4.1
1235
16
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);
17
Requires: The calling thread does not own the mutex for any ownership mode.
18
Effects: Constructs an object of type shared_lock and calls m.try_lock_shared_for(rel_time).
19
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();
20
Effects: If owns calls pm->unlock_shared().
shared_lock(shared_lock&& sl) noexcept;
21
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;
22
Effects: If owns calls pm->unlock_shared().
23
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.
33.4.4.4.2
shared_lock locking
[thread.lock.shared.locking]
void lock();
1
Effects: As if by pm->lock_shared().
2
Postconditions: owns == true.
3
Throws: Any exception thrown by pm->lock_shared(). system_error when an exception is required
(33.2.2).
4
Error conditions:
(4.1)
—
operation_not_permitted — if pm is nullptr.
(4.2)
—
resource_deadlock_would_occur — if on entry owns is true.
bool try_lock();
5
Effects: As if by pm->try_lock_shared().
6
Returns: The value returned by the call to pm->try_lock_shared().
7
Postconditions: owns == res, where res is the value returned by the call to pm->try_lock_shared().
8
Throws: Any exception thrown by pm->try_lock_shared(). system_error when an exception is
required (33.2.2).
9
Error conditions:
(9.1)
—
operation_not_permitted — if pm is nullptr.
(9.2)
—
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);
10
Effects: As if by pm->try_lock_shared_until(abs_time).
11
Returns: The value returned by the call to pm->try_lock_shared_until(abs_time).
12
Postconditions: owns == res, where res is the value returned by the call to pm->try_lock_shared_-
until(abs_time).
13
Throws: Any exception thrown by pm->try_lock_shared_until(abs_time). system_error when an
exception is required (33.2.2).
14
Error conditions:
§ 33.4.4.4.2
1236
(14.1)
—
operation_not_permitted — if pm is nullptr.
(14.2)
—
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);
15
Effects: As if by pm->try_lock_shared_for(rel_time).
16
Returns: The value returned by the call to pm->try_lock_shared_for(rel_time).
17
Postconditions: owns == res, where res is the value returned by the call to pm->try_lock_shared_-
for(rel_time).
18
Throws: Any exception thrown by pm->try_lock_shared_for(rel_time). system_error when an
exception is required (33.2.2).
19
Error conditions:
(19.1)
—
operation_not_permitted — if pm is nullptr.
(19.2)
—
resource_deadlock_would_occur — if on entry owns is true.
void unlock();
20
Effects: As if by pm->unlock_shared().
21
Postconditions: owns == false.
22
Throws: system_error when an exception is required (33.2.2).
23
Error conditions:
(23.1)
—
operation_not_permitted — if on entry owns is false.
33.4.4.4.3
shared_lock modifiers
[thread.lock.shared.mod]
void swap(shared_lock& sl) noexcept;
1
Effects: Swaps the data members of *this and sl.
mutex_type* release() noexcept;
2
Returns: The previous value of pm.
3
Postconditions: pm == nullptr and owns == false.
template<class Mutex>
void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
4
Effects: As if by x.swap(y).
33.4.4.4.4
shared_lock observers
[thread.lock.shared.obs]
bool owns_lock() const noexcept;
1
Returns: owns.
explicit operator bool() const noexcept;
2
Returns: owns.
mutex_type* mutex() const noexcept;
3
Returns: pm.
33.4.5
Generic locking algorithms
[thread.lock.algorithm]
template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
1
Requires: Each template parameter type shall meet the Lockable requirements. [ Note: The unique_-
lock class template meets these requirements when suitably instantiated.
— end note ]
2
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() shall be called for all prior arguments and there shall be no
further calls to try_lock().
§ 33.4.5
1237
3
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&...);
4
Requires: Each template parameter type shall meet the Lockable requirements, [ Note: The unique_-
lock class template meets these requirements when suitably instantiated.
— end note ]
5
Effects: All arguments are locked via a sequence of calls to lock(), try_lock(), or unlock() on each
argument. The sequence of calls shall not result in deadlock, but is otherwise unspecified. [Note: A
deadlock avoidance algorithm such as try-and-back-off must 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() shall be called for any argument that had been locked by a call to
lock() or try_lock().
33.4.6
Call once
[thread.once]
33.4.6.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;
};
}
1
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;
2
Effects: Constructs an object of type once_flag.
3
Synchronization: The construction of a once_flag object is not synchronized.
4
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.
33.4.6.2
Function call_once
[thread.once.callonce]
template<class Callable, class... Args>
void call_once(once_flag& flag, Callable&& func, Args&&... args);
1
Requires:
INVOKE(std::forward<Callable>(func), std::forward<Args>(args)...)
(see 23.14.3) shall be a valid expression.
2
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 shall call 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 shall
propagate the exception to the caller of call_once. Among all executions of call_once for any given
once_flag: at most one shall be a returning execution; if there is a returning execution, it shall be the
last active execution; and there are passive executions only if there is a returning execution. [Note:
Passive executions allow other threads to reliably observe the results produced by the earlier returning
execution.
— end note ]
3
Synchronization: For any given once_flag: all active executions occur in a total order; completion
of an active execution synchronizes with (6.8.2) the start of the next one in this total order; and the
returning execution synchronizes with the return from all passive executions.
4
Throws: system_error when an exception is required (33.2.2), or any exception thrown by func.
5
[ Example:
// global flag, regular function
void init();
std::once_flag flag;
§ 33.4.6.2
1238
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 ]
33.5
Condition variables
[thread.condition]
1
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 maximum efficiency
on some platforms. Class condition_variable_any provides a general condition variable that can wait on
objects of user-supplied lock types.
2
Condition variables permit concurrent invocation of the wait, wait_for, wait_until, notify_one and
notify_all member functions.
3
The execution of notify_one and notify_all shall be atomic. The execution of wait, wait_for, and
wait_until shall be 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.
4
The implementation shall behave 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.
5
Condition variable construction and destruction need not be synchronized.
33.5.1
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 };
}
33.5.2
Non-member functions
[thread.condition.nonmember]
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
1
Requires: lk is locked by the calling thread and either
(1.1)
—
no other thread is waiting on cond, or
§ 33.5.2
1239
(1.2)
—
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.
2
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 shall be as if:
lk.unlock();
cond.notify_all();
3
Synchronization: The implied lk.unlock() call is sequenced after the destruction of all objects with
thread storage duration associated with the current thread.
4
[Note: The supplied lock will be held until the thread exits, and care should be taken to ensure that
this does not cause deadlock due to lock ordering issues. After calling notify_all_at_thread_exit
it is recommended that the thread should be exited as soon as possible, and that no blocking or
time-consuming tasks are run on that thread.
— end note ]
5
[ Note: It is the user’s responsibility to ensure that waiting threads do not erroneously assume that the
thread has finished if they experience spurious wakeups. This typically requires that the condition being
waited for is satisfied while holding the lock on lk, and that this lock is not released and reacquired
prior to calling notify_all_at_thread_exit.
— end note ]
33.5.3
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 33.2.3
native_handle_type native_handle();
// see 33.2.3
};
}
1
The class condition_variable shall be a standard-layout class (Clause 12).
condition_variable();
2
Effects: Constructs an object of type condition_variable.
3
Throws: system_error when an exception is required (33.2.2).
4
Error conditions:
§ 33.5.3
1240
(4.1)
—
resource_unavailable_try_again — if some non-memory resource limitation prevents initial-
ization.
~condition_variable();
5
Requires: There shall be no thread blocked on *this.
[Note: That is, all threads shall have been
notified; they may 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. The user should take care to ensure that no threads wait
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 ]
6
Effects: Destroys the object.
void notify_one() noexcept;
7
Effects: If any threads are blocked waiting for *this, unblocks one of those threads.
void notify_all() noexcept;
8
Effects: Unblocks all threads that are blocked waiting for *this.
void wait(unique_lock<mutex>& lock);
9
Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
(9.1)
—
no other thread is waiting on this condition_variable object or
(9.2)
—
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.
10
Effects:
(10.1)
—
Atomically calls lock.unlock() and blocks on *this.
(10.2)
—
When unblocked, calls lock.lock() (possibly blocking on the lock), then returns.
(10.3)
—
The function will unblock when signaled by a call to notify_one() or a call to notify_all(), or
spuriously.
11
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
12
Postconditions: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
13
Throws: Nothing.
template<class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred);
14
Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
(14.1)
—
no other thread is waiting on this condition_variable object or
(14.2)
—
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.
15
Effects: Equivalent to:
while (!pred())
wait(lock);
16
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
17
Postconditions: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
18
Throws: Any exception thrown by pred.
template<class Clock, class Duration>
cv_status wait_until(unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& abs_time);
19
Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
(19.1)
—
no other thread is waiting on this condition_variable object or
§ 33.5.3
1241
(19.2)
—
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.
20
Effects:
(20.1)
—
Atomically calls lock.unlock() and blocks on *this.
(20.2)
—
When unblocked, calls lock.lock() (possibly blocking on the lock), then returns.
(20.3)
—
The function will unblock when signaled by a call to notify_one(), a call to notify_all(),
expiration of the absolute timeout (33.2.4) specified by abs_time, or spuriously.
(20.4)
—
If the function exits via an exception, lock.lock() shall be called prior to exiting the function.
21
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
22
Postconditions: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
23
Returns: cv_status::timeout if the absolute timeout (33.2.4) specified by abs_time expired, otherwise
cv_status::no_timeout.
24
Throws: Timeout-related exceptions (33.2.4).
template<class Rep, class Period>
cv_status wait_for(unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& rel_time);
25
Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
(25.1)
—
no other thread is waiting on this condition_variable object or
(25.2)
—
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.
26
Effects: Equivalent to:
return wait_until(lock, chrono::steady_clock::now() + rel_time);
27
Returns: cv_status::timeout if the relative timeout (33.2.4) specified by rel_time expired, otherwise
cv_status::no_timeout.
28
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
29
Postconditions: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
30
Throws: Timeout-related exceptions (33.2.4).
template<class Clock, class Duration, class Predicate>
bool wait_until(unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& abs_time,
Predicate pred);
31
Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
(31.1)
—
no other thread is waiting on this condition_variable object or
(31.2)
—
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.
32
Effects: Equivalent to:
while (!pred())
if (wait_until(lock, abs_time) == cv_status::timeout)
return pred();
return true;
33
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
34
Postconditions: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
35
[ Note: The returned value indicates whether the predicate evaluated to true regardless of whether the
timeout was triggered.
— end note ]
36
Throws: Timeout-related exceptions (33.2.4) or any exception thrown by pred.
§ 33.5.3
1242
template<class Rep, class Period, class Predicate>
bool wait_for(unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& rel_time,
Predicate pred);
37
Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
(37.1)
—
no other thread is waiting on this condition_variable object or
(37.2)
—
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.
38
Effects: Equivalent to:
return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
39
[ Note: There is no blocking if pred() is initially true, even if the timeout has already expired.
— end
note ]
40
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
41
Postconditions: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
42
[ Note: The returned value indicates whether the predicate evaluates to true regardless of whether the
timeout was triggered.
— end note ]
43
Throws: Timeout-related exceptions (33.2.4) or any exception thrown by pred.
33.5.4
Class condition_variable_any
[thread.condition.condvarany]
1
A Lock type shall meet the BasicLockable requirements (33.2.5.2). [ Note: 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, the user should ensure that any necessary
synchronization is 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;
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);
};
}
condition_variable_any();
2
Effects: Constructs an object of type condition_variable_any.
3
Throws: bad_alloc or system_error when an exception is required (33.2.2).
§ 33.5.4
1243
4
Error conditions:
(4.1)
—
resource_unavailable_try_again — if some non-memory resource limitation prevents initial-
ization.
(4.2)
—
operation_not_permitted — if the thread does not have the privilege to perform the operation.
~condition_variable_any();
5
Requires: There shall be no thread blocked on *this.
[Note: That is, all threads shall have been
notified; they may 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. The user should take care to ensure that no threads wait
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 ]
6
Effects: Destroys the object.
void notify_one() noexcept;
7
Effects: If any threads are blocked waiting for *this, unblocks one of those threads.
void notify_all() noexcept;
8
Effects: Unblocks all threads that are blocked waiting for *this.
template<class Lock>
void wait(Lock& lock);
9
Effects:
(9.1)
—
Atomically calls lock.unlock() and blocks on *this.
(9.2)
—
When unblocked, calls lock.lock() (possibly blocking on the lock) and returns.
(9.3)
—
The function will unblock when signaled by a call to notify_one(), a call to notify_all(), or
spuriously.
10
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
11
Postconditions: lock is locked by the calling thread.
12
Throws: Nothing.
template<class Lock, class Predicate>
void wait(Lock& lock, Predicate pred);
13
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);
14
Effects:
(14.1)
—
Atomically calls lock.unlock() and blocks on *this.
(14.2)
—
When unblocked, calls lock.lock() (possibly blocking on the lock) and returns.
(14.3)
—
The function will unblock when signaled by a call to notify_one(), a call to notify_all(),
expiration of the absolute timeout (33.2.4) specified by abs_time, or spuriously.
(14.4)
—
If the function exits via an exception, lock.lock() shall be called prior to exiting the function.
15
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
16
Postconditions: lock is locked by the calling thread.
17
Returns: cv_status::timeout if the absolute timeout (33.2.4) specified by abs_time expired, otherwise
cv_status::no_timeout.
18
Throws: Timeout-related exceptions (33.2.4).
§ 33.5.4
1244
template<class Lock, class Rep, class Period>
cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
19
Effects: Equivalent to:
return wait_until(lock, chrono::steady_clock::now() + rel_time);
20
Returns: cv_status::timeout if the relative timeout (33.2.4) specified by rel_time expired, otherwise
cv_status::no_timeout.
21
Remarks: If the function fails to meet the postcondition, terminate() shall be called (18.5.1). [ Note:
This can happen if the re-locking of the mutex throws an exception.
— end note ]
22
Postconditions: lock is locked by the calling thread.
23
Throws: Timeout-related exceptions (33.2.4).
template<class Lock, class Clock, class Duration, class Predicate>
bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
24
Effects: Equivalent to:
while (!pred())
if (wait_until(lock, abs_time) == cv_status::timeout)
return pred();
return true;
25
[Note: There is no blocking if pred() is initially true, or if the timeout has already expired.
— end
note ]
26
[ Note: 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);
27
Effects: Equivalent to:
return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
33.6
Futures
[futures]
33.6.1
Overview
[futures.overview]
1
33.6 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: These components are not
restricted to multi-threaded programs but can be useful in single-threaded programs as well.
— end note ]
33.6.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
};
§ 33.6.2
1245
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);
}
1
The enum type launch is a bitmask type (20.4.2.1.4) with elements launch::async and launch::deferred.
[ Note: 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 ]
2
The enum values of future_errc are distinct and not zero.
33.6.3
Error handling
[futures.errors]
const error_category& future_category() noexcept;
1
Returns: A reference to an object of a type derived from class error_category.
2
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 shall return a pointer to the string
"future".
error_code make_error_code(future_errc e) noexcept;
3
Returns: error_code(static_cast<int>(e), future_category()).
error_condition make_error_condition(future_errc e) noexcept;
4
Returns: error_condition(static_cast<int>(e), future_category()).
§ 33.6.3
1246
33.6.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);
1
Effects: Constructs an object of class future_error and initializes ec_ with make_error_code(e).
const error_code& code() const noexcept;
2
Returns: ec_.
const char* what() const noexcept;
3
Returns: An ntbs incorporating code().message().
33.6.5
Shared state
[futures.state]
1
Many of the classes introduced in this subclause 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: Futures, promises, and tasks defined in this clause reference such shared
state.
— end note ]
2
[Note: 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 ]
3
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 (33.2.5), then it is a timed
waiting function, otherwise it is a non-timed waiting function.
4
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: 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.
5
When an asynchronous return object or an asynchronous provider is said to release its shared state, it means:
(5.1)
—
if the return object or provider holds the last reference to its shared state, the shared state is destroyed;
and
(5.2)
—
the return object or provider gives up its reference to its shared state; and
(5.3)
—
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.
6
When an asynchronous provider is said to make its shared state ready, it means:
(6.1)
—
first, the provider marks its shared state as ready; and
(6.2)
—
second, the provider unblocks any execution agents waiting for its shared state to become ready.
7
When an asynchronous provider is said to abandon its shared state, it means:
(7.1)
—
first, if that state is not ready, the provider
(7.1.1)
—
stores an exception object of type future_error with an error condition of broken_promise
within its shared state; and then
(7.1.2)
—
makes its shared state ready;
(7.2)
—
second, the provider releases its shared state.
§ 33.6.5
1247
8
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.
9
Calls to functions that successfully set the stored result of a shared state synchronize with (6.8.2) 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 (6.8.2) the successful return from a call to a
waiting function on the shared state.
10
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 (6.6.4.2) is
sequenced before making that shared state ready.
11
Access to the result of the same shared state may conflict (6.8.2). [ Note: This explicitly specifies that the result
of the shared state is visible in the objects that reference this state in the sense of data race avoidance (20.5.5.9).
For example, concurrent accesses through references returned by shared_future::get() (33.6.8) must either
use read-only operations or provide additional synchronization.
— end note ]
33.6.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& rhs) = delete;
~promise();
// assignment
promise& operator=(promise&& rhs) noexcept;
promise& operator=(const promise& rhs) = 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>;
}
1
The implementation shall provide 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.
2
The set_value, set_exception, set_value_at_thread_exit, and set_exception_at_thread_exit mem-
ber 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>
§ 33.6.6
1248
: true_type { };
3
Requires: Alloc shall be an Allocator (20.5.3.5).
promise();
template<class Allocator>
promise(allocator_arg_t, const Allocator& a);
4
Effects: Constructs a promise object and a shared state. The second constructor uses the allocator a
to allocate memory for the shared state.
promise(promise&& rhs) noexcept;
5
Effects: Constructs a new promise object and transfers ownership of the shared state of rhs (if any)
to the newly-constructed object.
6
Postconditions: rhs has no shared state.
~promise();
7
Effects: Abandons any shared state (33.6.5).
promise& operator=(promise&& rhs) noexcept;
8
Effects: Abandons any shared state (33.6.5) and then as if promise(std::move(rhs)).swap(*this).
9
Returns: *this.
void swap(promise& other) noexcept;
10
Effects: Exchanges the shared state of *this and other.
11
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();
12
Returns: A future<R> object with the same shared state as *this.
13
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.
14
Error conditions:
(14.1)
—
future_already_retrieved if get_future has already been called on a promise with the same
shared state as *this.
(14.2)
—
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();
15
Effects: Atomically stores the value r in the shared state and makes that state ready (33.6.5).
16
Throws:
(16.1)
—
future_error if its shared state already has a stored value or exception, or
(16.2)
—
for the first version, any exception thrown by the constructor selected to copy an object of R, or
(16.3)
—
for the second version, any exception thrown by the constructor selected to move an object of R.
17
Error conditions:
(17.1)
—
promise_already_satisfied if its shared state already has a stored value or exception.
(17.2)
—
no_state if *this has no shared state.
void
set_exception(exception_ptr p);
18
Requires: p is not null.
19
Effects: Atomically stores the exception pointer p in the shared state and makes that state ready (33.6.5).
20
Throws: future_error if its shared state already has a stored value or exception.
21
Error conditions:
§ 33.6.6
1249
(21.1)
—
promise_already_satisfied if its shared state already has a stored value or exception.
(21.2)
—
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();
22
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.
23
Throws:
(23.1)
—
future_error if its shared state already has a stored value or exception, or
(23.2)
—
for the first version, any exception thrown by the constructor selected to copy an object of R, or
(23.3)
—
for the second version, any exception thrown by the constructor selected to move an object of R.
24
Error conditions:
(24.1)
—
promise_already_satisfied if its shared state already has a stored value or exception.
(24.2)
—
no_state if *this has no shared state.
void
set_exception_at_thread_exit(exception_ptr p);
25
Requires: p is not null.
26
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.
27
Throws: future_error if an error condition occurs.
28
Error conditions:
(28.1)
—
promise_already_satisfied if its shared state already has a stored value or exception.
(28.2)
—
no_state if *this has no shared state.
template<class R>
void swap(promise<R>& x, promise<R>& y) noexcept;
29
Effects: As if by x.swap(y).
33.6.7
Class template future
[futures.unique_future]
1
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 (33.6.5) 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.
2
[Note: Member functions of future do not synchronize with themselves or with member functions of
shared_future. — end note ]
3
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: It is valid to move from a
future object for which valid() == false.
— end note ] [Note: Implementations should detect this case
and throw an object of type future_error with an error condition of future_errc::no_state.
— end
note ]
namespace std {
template<class R>
class future {
public:
future() noexcept;
future(future&&) noexcept;
future(const future& rhs) = delete;
~future();
§ 33.6.7
1250
future& operator=(const future& rhs) = 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;
};
}
4
The implementation shall provide 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;
5
Effects: Constructs an empty future object that does not refer to a shared state.
6
Postconditions: valid() == false.
future(future&& rhs) noexcept;
7
Effects: Move constructs a future object that refers to the shared state that was originally referred to
by rhs (if any).
8
Postconditions:
(8.1)
—
valid() returns the same value as rhs.valid() prior to the constructor invocation.
(8.2)
—
rhs.valid() == false.
~future();
9
Effects:
(9.1)
—
Releases any shared state (33.6.5);
(9.2)
—
destroys *this.
future& operator=(future&& rhs) noexcept;
10
Effects:
(10.1)
—
Releases any shared state (33.6.5).
(10.2)
—
move assigns the contents of rhs to *this.
11
Postconditions:
(11.1)
—
valid() returns the same value as rhs.valid() prior to the assignment.
(11.2)
—
rhs.valid() == false.
shared_future<R> share() noexcept;
12
Returns: shared_future<R>(std::move(*this)).
13
Postconditions: valid() == false.
R future::get();
R& future<R&>::get();
void future<void>::get();
14
[ Note: 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 ]
15
Effects:
§ 33.6.7
1251
|
|