[
Note: These threads are intended to map one-to-one with operating system threads
. —
end note ]
namespace std {
class thread;
void swap(thread& x, thread& y) noexcept;
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);
}
}
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: 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:
class id;
using native_handle_type = implementation-defined;
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;
void swap(thread&) noexcept;
bool joinable() const noexcept;
void join();
void detach();
id get_id() const noexcept;
native_handle_type native_handle();
static unsigned hardware_concurrency() noexcept;
};
}
namespace std {
class thread::id {
public:
id() noexcept;
};
bool operator==(thread::id x, thread::id y) noexcept;
bool operator!=(thread::id x, thread::id y) noexcept;
bool operator<(thread::id x, thread::id y) noexcept;
bool operator<=(thread::id x, thread::id y) noexcept;
bool operator>(thread::id x, thread::id y) noexcept;
bool operator>=(thread::id x, thread::id y) noexcept;
template<class charT, class traits>
basic_ostream<charT, traits>&
operator<< (basic_ostream<charT, traits>& out, thread::id id);
template <class 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 shall be a trivially copyable class (Clause
[class])
. The library may reuse the value of a
thread::id of a terminated thread that can no longer be joined
.[
Note: Relational operators allow
thread::id objects to be used as
keys in associative containers
. —
end note ]
id() noexcept;
Effects: Constructs an object of type
id. 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
. bool operator!=(thread::id x, thread::id y) noexcept;
bool operator<(thread::id x, thread::id y) noexcept;
Returns: A value such that
operator< is a total ordering as described in
[alg.sorting]. bool operator<=(thread::id x, thread::id y) noexcept;
bool operator>(thread::id x, thread::id y) noexcept;
bool 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);
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 shall have the same text
representation and if
x != y the
thread::id objects shall have
distinct text representations
.template <> struct hash<thread::id>;
thread() noexcept;
Effects: Constructs a
thread object that does not represent a thread of execution
. Postconditions: get_id() == id(). template <class F, class... Args> explicit thread(F&& f, Args&&... args);
Requires: F and each
Ti in
Args shall satisfy the
MoveConstructible requirements
. INVOKE(DECAY_COPY(std::forward<F>(f)),
DECAY_COPY(std::forward<Args>(args))...) (
[func.require]) shall be
a valid expression
. Remarks:
This constructor shall not participate in overload resolution if
decay_t<F>
is the same type as
std::thread. Effects: Constructs an object of type
thread. 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: 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(DECAY_COPY(std::forward<F>(f)),
DECAY_COPY(std::forward<Args>(args))...)
terminates with an uncaught exception,
terminate shall be 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;
Effects: Constructs an object of type
thread from
x, 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 start of construction
. ~thread();
If
joinable(), calls
terminate(). Otherwise, has no effects
. [
Note: 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
. Thus the programmer must
ensure that the destructor is never executed while the thread is still joinable
. —
end note ]
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
. 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: Operations on
*this are not synchronized
. —
end note ]
Postconditions: The thread represented by
*this has completed
. 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 shall release any owned resources
.Postconditions: get_id() == id(). 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. unsigned hardware_concurrency() noexcept;
Returns: The number of hardware thread contexts
. [
Note: This value should
only be considered to be a hint
. —
end note ]
If this value is not computable or
well defined an implementation should return 0
.void swap(thread& x, thread& y) noexcept;
Effects: As if by
x.swap(y).
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 shall have this id and this thread of execution shall
always have this id
. The object returned shall not compare equal to a default constructed
thread::id.void this_thread::yield() noexcept;
Effects: Offers the implementation the opportunity to reschedule
. 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. 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. 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
.Condition variables permit concurrent invocation of the
wait,
wait_for,
wait_until,
notify_one and
notify_all member functions
.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
.
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
.Condition variable construction and destruction need not be synchronized
.
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 };
}
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
Requires: lk is locked by the calling thread and either
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();
Synchronization: The implied
lk.unlock() call is sequenced after the destruction of
all objects with thread storage duration associated with the current thread
. [
Note: The supplied lock will be held until the thread exits, and care
must 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 ]
[
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 ]
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; native_handle_type native_handle(); };
}
The class
condition_variable shall be a standard-layout class (Clause
[class])
. condition_variable();
Effects: Constructs an object of type
condition_variable. Error conditions:
resource_unavailable_try_again — if some non-memory resource
limitation prevents initialization
.
~condition_variable();
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 must happen before destruction
. The user must 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 ]
Effects: Destroys the object
. 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);
Requires: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread, and either
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
.
Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
Postconditions: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread
. template <class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred);
Requires: lock.owns_lock() is true and lock.mutex() is
locked by the calling thread, and either
Effects: Equivalent to:
while (!pred())
wait(lock);
Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
Postconditions: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread
. 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);
Requires: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread, and either
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() shall be called prior to exiting the function
.
Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
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. template <class Rep, class Period>
cv_status wait_for(unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& rel_time);
Requires: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread, and either
Effects: Equivalent to:
return wait_until(lock, chrono::steady_clock::now() + rel_time);
Returns: cv_status::timeout if
the relative timeout (
[thread.req.timing]) specified by
rel_time expired,
otherwise
cv_status::no_timeout. Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
Postconditions: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread
. template <class Clock, class Duration, class Predicate>
bool wait_until(unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& abs_time,
Predicate pred);
Requires: lock.owns_lock() is true and lock.mutex() is
locked by the calling thread, and either
Effects: Equivalent to:
while (!pred())
if (wait_until(lock, abs_time) == cv_status::timeout)
return pred();
return true;
Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
Postconditions: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread
. [
Note: The returned value indicates whether the predicate evaluated to
true regardless of whether the timeout was triggered
. —
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);
Requires: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread, and either
Effects: Equivalent to:
return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
[
Note: There is no blocking if
pred() is initially
true, even if the
timeout has already expired
. —
end note ]
Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
Postconditions: lock.owns_lock() is
true and
lock.mutex()
is locked by the calling thread
. [
Note: The returned value indicates whether the predicate evaluates to
true
regardless of whether the timeout was triggered
. —
end note ]
[
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 must 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();
Effects: Constructs an object of type
condition_variable_any. 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();
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 must happen before destruction
. The user must 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 ]
Effects: Destroys the object
. 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. template <class Lock>
void wait(Lock& lock);
[
Note: If any of the
wait functions exits via an exception, it is
unspecified whether the
Lock is held
. One can use a
Lock type
that allows to query that, such as the
unique_lock wrapper
. —
end note ]
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
.
Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
Postconditions: lock is locked by the calling thread
. 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() shall be called prior to exiting the function
.
Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
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. 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);
Returns: cv_status::timeout if
the relative timeout (
[thread.req.timing]) specified by
rel_time expired,
otherwise
cv_status::no_timeout. Remarks:
If the function fails to meet the postcondition,
terminate()
shall be called (
[except.terminate])
. [
Note: This can happen if the re-locking of the mutex throws an exception
. —
end note ]
Postconditions: lock is locked by the calling thread
. 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: There is no blocking if
pred() is initially
true, or
if the timeout has already expired
. —
end note ]
[
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);
Effects: Equivalent to:
return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
[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: These components are not restricted to multi-threaded programs but can be useful in
single-threaded programs as well
. —
end note ]
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; 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 R, class Alloc>
struct uses_allocator<packaged_task<R>, Alloc>;
template <class F, class... Args>
future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
async(F&& f, Args&&... args);
template <class F, class... Args>
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 (
[bitmask.types]) 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 ]
The enum values of
future_errc are distinct and not zero
.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 shall return 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()).
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_; };
}
explicit future_error(future_errc e);
Effects: Constructs an object of class
future_error
and initializes
ec_ with
make_error_code(e). const error_code& code() const noexcept;
const char* what() const noexcept;
Returns: An
ntbs incorporating
code().message(). 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 ]
[
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 ]
A
waiting function of an asynchronous return object is one
that potentially blocks to wait for the shared state to be made
ready
. 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
. 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:
When an asynchronous provider is said to abandon its shared state, it means:
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 (
[intro.multithread]) calls to functions
successfully detecting the ready state resulting from that setting
. The storage of the result
(whether normal or exceptional) into the shared state
synchronizes with (
[intro.multithread])
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 (
[basic.stc.thread])
is sequenced before making that shared state ready
. [
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 (
[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 ]
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();
promise& operator=(promise&& rhs) noexcept;
promise& operator=(const promise& rhs) = delete;
void swap(promise& other) noexcept;
future<R> get_future();
void set_value(see below);
void set_exception(exception_ptr p);
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 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
.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 { };
promise();
template <class Allocator>
promise(allocator_arg_t, const Allocator& a);
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;
Effects: constructs a new
promise object and transfers ownership of the shared state
of
rhs (if any) to the newly-constructed object
. Postconditions: rhs has no shared state
. ~promise();
promise& operator=(promise&& rhs) noexcept;
Effects:
Abandons any shared state (
[futures.state]) and then as if
promise(std::move(rhs)).swap(*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. 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);
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);
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). 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 (
[futures.state]) 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: 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: It is valid to move from a future object for which
valid() == false. —
end note ]
[
Note: Implementations are encouraged to 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();
future& operator=(const future& rhs) = delete;
future& operator=(future&&) noexcept;
shared_future<R> share() noexcept;
see below get();
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 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;
Effects: Constructs an
empty
future object that 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
.
~future();
future& operator=(future&& rhs) noexcept;
Effects:
move assigns the contents of
rhs to
*this.
Postconditions:
valid() returns the same value as
rhs.valid() prior to the
assignment
.
shared_future<R> share() noexcept;
Returns: shared_future<R>(std::move(*this)). Postconditions: valid() == false. R future::get();
R& future<R&>::get();
void future<void>::get();
[
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 ]
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
. Postconditions: valid() == false. 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
.
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
.
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 (
[futures.state]) 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: 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: It is valid to copy or move from a
shared_future
object for which
valid() is
false. —
end note ]
[
Note: Implementations are encouraged to 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 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;
see below get() const;
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 shall provide 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: Constructs an
empty shared_future object that does not refer to a
shared state
. Postconditions: valid() == false. shared_future(const shared_future& rhs) noexcept;
Effects: Constructs a
shared_future object that 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
.
~shared_future();
shared_future& operator=(shared_future&& rhs) noexcept;
Effects:
move assigns the contents of
rhs to
*this.
Postconditions:
valid() returns the same value as
rhs.valid() returned prior to
the assignment
.
shared_future& operator=(const shared_future& rhs) noexcept;
Effects:
assigns the contents of
rhs to
*this. [
Note: 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: 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: Access to a value object stored in the shared state is
unsynchronized, so programmers should apply only those operations on
R that do not
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: 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
.
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
.
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>
future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
async(F&& f, Args&&... args);
template <class F, class... Args>
future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
async(launch policy, F&& f, Args&&... args);
Requires: F and each
Ti in
Args shall
satisfy the
MoveConstructible requirements, and
INVOKE(DECAY_COPY(std::forward<F>(f)),
DECAY_COPY(std::forward<Args>(args))...)
shall be a valid expression
. 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
. 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 shall invoke 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
. [
Note: 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
. —
end note ]
If no value is set in the launch policy, or a value is set that is neither specified
in this International Standard 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: If a future obtained from
async is moved outside the local scope,
other code that uses the future must be aware that the future's destructor may
block for the shared state to become ready
. —
end note ]
Synchronization:
Regardless of the provided
policy argument,
-
[
Note: This statement applies even when the corresponding
future object is moved to
another thread
. —
end note ]
; and
the completion of the function
f is sequenced before (
[intro.multithread]) the
shared state is made ready
. [
Note: 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 (
[intro.multithread])
the return from
the first function
that successfully detects the ready status of the shared state or
with the return from the last
function that releases the shared state, whichever
happens first
.
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:
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(); }
[
Note: Line #1 might not result in concurrency because
the
async call uses the default policy, which may 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 ]
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;
template<class R, class... ArgTypes>
class packaged_task<R(ArgTypes...)> {
public:
packaged_task() noexcept;
template <class F>
explicit packaged_task(F&& f);
~packaged_task();
packaged_task(const packaged_task&) = delete;
packaged_task& operator=(const packaged_task&) = delete;
packaged_task(packaged_task&& rhs) noexcept;
packaged_task& operator=(packaged_task&& rhs) noexcept;
void swap(packaged_task& other) noexcept;
bool valid() const noexcept;
future<R> get_future();
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;
template <class R, class Alloc>
struct uses_allocator<packaged_task<R>, Alloc>;
}
packaged_task() noexcept;
Effects: Constructs a
packaged_task object with no shared state and no stored task
. template <class F>
packaged_task(F&& f);
Requires:
INVOKE<R>(f, t1, t2, ..., tN), where
t1, t2, ..., tN are values
of the corresponding types in
ArgTypes..., shall be a valid expression
. Invoking
a copy of
f shall behave the same as invoking
f.Remarks:
This constructor shall not participate in overload resolution if
decay_t<F>
is the same type as
packaged_task<R(ArgTypes...)>. 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.For the first version,
bad_alloc if memory for the internal data structures could not be allocated
.For the second version,
any exceptions thrown by
allocator_traits<Allocator>::template
rebind_traits<unspecified>::allocate.
packaged_task(packaged_task&& rhs) noexcept;
Effects: Constructs a new
packaged_task object and 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:
calls
packaged_task(std::move(rhs)).swap(*this).
~packaged_task();
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. 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, t1, t2, ..., tN),
where
f is the
stored task of
*this and
t1, t2, ..., tN 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, t1, t2, ..., tN),
where
f is the stored task and
t1, t2, ..., tN 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 shall be 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: This constructs a new shared state for
*this. —
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
.
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). template <class R, class Alloc>
struct uses_allocator<packaged_task<R>, Alloc>
: true_type { };