2004 lines
74 KiB
Markdown
2004 lines
74 KiB
Markdown
[futures]
|
||
|
||
# 32 Concurrency support library [[thread]](./#thread)
|
||
|
||
## 32.10 Futures [futures]
|
||
|
||
### [32.10.1](#overview) Overview [[futures.overview]](futures.overview)
|
||
|
||
[1](#overview-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11126)
|
||
|
||
[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[.](#overview-1.sentence-1)
|
||
|
||
[*Note [1](#overview-note-1)*:
|
||
|
||
These components are not restricted to multi-threaded programs but can be useful in
|
||
single-threaded programs as well[.](#overview-1.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
### [32.10.2](#future.syn) Header <future> synopsis [[future.syn]](future.syn)
|
||
|
||
[ð](#header:%3cfuture%3e)
|
||
|
||
namespace std {enum class [future_errc](#lib:future_errc "32.10.2 Header <future> synopsis [future.syn]") {[broken_promise](#lib:future_errc,broken_promise "32.10.2 Header <future> synopsis [future.syn]") = *implementation-defined*, [future_already_retrieved](#lib:future_errc,future_already_retrieved "32.10.2 Header <future> synopsis [future.syn]") = *implementation-defined*, [promise_already_satisfied](#lib:future_errc,promise_already_satisfied "32.10.2 Header <future> synopsis [future.syn]") = *implementation-defined*, [no_state](#lib:future_errc,no_state "32.10.2 Header <future> synopsis [future.syn]") = *implementation-defined*}; enum class [launch](#lib:launch "32.10.2 Header <future> synopsis [future.syn]") : *unspecified* {[async](#lib:launch,async "32.10.2 Header <future> synopsis [future.syn]") = *unspecified*, [deferred](#lib:launch,deferred "32.10.2 Header <future> synopsis [future.syn]") = *unspecified*, *implementation-defined*}; enum class [future_status](#lib:future_status "32.10.2 Header <future> synopsis [future.syn]") {[ready](#lib:future_status,ready "32.10.2 Header <future> synopsis [future.syn]"), [timeout](#lib:future_status,timeout "32.10.2 Header <future> synopsis [future.syn]"), [deferred](#lib:future_status,deferred "32.10.2 Header <future> synopsis [future.syn]")}; // [[futures.errors]](#errors "32.10.3 Error handling"), error handlingtemplate<> 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; // [[futures.future.error]](#future.error "32.10.4 Class future_error"), class future_errorclass future_error; // [[futures.promise]](#promise "32.10.6 Class template promise"), class template promisetemplate<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; // [[futures.unique.future]](#unique.future "32.10.7 Class template future"), class template futuretemplate<class R> class future; template<class R> class future<R&>; template<> class future<void>; // [[futures.shared.future]](#shared.future "32.10.8 Class template shared_future"), class template shared_futuretemplate<class R> class shared_future; template<class R> class shared_future<R&>; template<> class shared_future<void>; // [[futures.task]](#task "32.10.10 Class template packaged_task"), class template packaged_tasktemplate<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; // [[futures.async]](#async "32.10.9 Function template async"), function template asynctemplate<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);}
|
||
|
||
[1](#future.syn-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11204)
|
||
|
||
The enum type launch is a bitmask type ([[bitmask.types]](bitmask.types "16.3.3.3.3 Bitmask types")) with
|
||
elements launch::async and launch::deferred[.](#future.syn-1.sentence-1)
|
||
|
||
[*Note [1](#future.syn-note-1)*:
|
||
|
||
Implementations can provide bitmasks to specify restrictions on task
|
||
interaction by functions launched by async() applicable to a
|
||
corresponding subset of available launch policies[.](#future.syn-1.sentence-2)
|
||
|
||
Implementations can extend
|
||
the behavior of the first overload of async() by adding their extensions
|
||
to the launch policy under the âas ifâ rule[.](#future.syn-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#future.syn-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11215)
|
||
|
||
The enum values of future_errc are distinct and not zero[.](#future.syn-2.sentence-1)
|
||
|
||
### [32.10.3](#errors) Error handling [[futures.errors]](futures.errors)
|
||
|
||
[ð](#lib:future_category)
|
||
|
||
`const error_category& future_category() noexcept;
|
||
`
|
||
|
||
[1](#errors-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11226)
|
||
|
||
*Returns*: A reference to an object of a type derived from class error_category[.](#errors-1.sentence-1)
|
||
|
||
[2](#errors-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11230)
|
||
|
||
The object's default_error_condition and equivalent virtual functions shall
|
||
behave as specified for the class error_category[.](#errors-2.sentence-1)
|
||
|
||
The object's name virtual function returns a pointer to the string "future"[.](#errors-2.sentence-2)
|
||
|
||
[ð](#lib:make_error_code,future_errc)
|
||
|
||
`error_code make_error_code(future_errc e) noexcept;
|
||
`
|
||
|
||
[3](#errors-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11242)
|
||
|
||
*Returns*: error_code(static_cast<int>(e), future_category())[.](#errors-3.sentence-1)
|
||
|
||
[ð](#lib:make_error_condition,future_errc)
|
||
|
||
`error_condition make_error_condition(future_errc e) noexcept;
|
||
`
|
||
|
||
[4](#errors-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11253)
|
||
|
||
*Returns*: error_condition(static_cast<int>(e), future_category())[.](#errors-4.sentence-1)
|
||
|
||
### [32.10.4](#future.error) Class future_error [[futures.future.error]](futures.future.error)
|
||
|
||
[ð](#lib: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*};}
|
||
|
||
[ð](#lib:future_error,constructor)
|
||
|
||
`explicit future_error(future_errc e);
|
||
`
|
||
|
||
[1](#future.error-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11282)
|
||
|
||
*Effects*: Initializes ec_ with make_error_code(e)[.](#future.error-1.sentence-1)
|
||
|
||
[ð](#lib:code,future_error)
|
||
|
||
`const error_code& code() const noexcept;
|
||
`
|
||
|
||
[2](#future.error-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11293)
|
||
|
||
*Returns*: ec_[.](#future.error-2.sentence-1)
|
||
|
||
[ð](#lib:what,future_error)
|
||
|
||
`const char* what() const noexcept;
|
||
`
|
||
|
||
[3](#future.error-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11304)
|
||
|
||
*Returns*: An ntbs incorporating code().message()[.](#future.error-3.sentence-1)
|
||
|
||
### [32.10.5](#state) Shared state [[futures.state]](futures.state)
|
||
|
||
[1](#state-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11311)
|
||
|
||
Many of the classes introduced in subclause [futures] use some state to communicate results[.](#state-1.sentence-1)
|
||
|
||
This
|
||
|
||
[*shared state*](#def:future,shared_state "32.10.5 Shared state [futures.state]") consists of some state information and some (possibly not
|
||
yet evaluated) [*result*](#def:result), which can be a (possibly void) value or an exception[.](#state-1.sentence-2)
|
||
|
||
[*Note [1](#state-note-1)*:
|
||
|
||
Futures, promises, and tasks defined in this Clause reference such shared state[.](#state-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#state-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11320)
|
||
|
||
[*Note [2](#state-note-2)*:
|
||
|
||
The result can be any kind of object including a function to compute that result,
|
||
as used by async when policy is launch::deferred[.](#state-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[3](#state-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11326)
|
||
|
||
An [*asynchronous return object*](#def:asynchronous_return_object "32.10.5 Shared state [futures.state]") is an object that reads results from a
|
||
shared state[.](#state-3.sentence-1)
|
||
|
||
A [*waiting function*](#def:function,waiting "32.10.5 Shared state [futures.state]") of an asynchronous return object is one
|
||
that potentially blocks to wait for the shared state to be made
|
||
ready[.](#state-3.sentence-2)
|
||
|
||
If a waiting function can return before the state is made ready because of a
|
||
timeout ([[thread.req.lockable]](thread.req.lockable "32.2.5 Requirements for Cpp17Lockable types")), then it is a [*timed waiting function*](#def:timed_waiting_function), otherwise
|
||
it is a [*non-timed waiting function*](#def:non-timed_waiting_function)[.](#state-3.sentence-3)
|
||
|
||
[4](#state-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11335)
|
||
|
||
An [*asynchronous provider*](#def:asynchronous_provider "32.10.5 Shared state [futures.state]") is an object that provides a result to a shared
|
||
state[.](#state-4.sentence-1)
|
||
|
||
The result of a shared state is set by
|
||
respective functions on the asynchronous provider[.](#state-4.sentence-2)
|
||
|
||
[*Example [1](#state-example-1)*:
|
||
|
||
Promises and tasks are examples of asynchronous providers[.](#state-4.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
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[.](#state-4.sentence-4)
|
||
|
||
[5](#state-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11346)
|
||
|
||
When an asynchronous return object or an asynchronous provider is said to release its
|
||
shared state, it means:
|
||
|
||
- [(5.1)](#state-5.1)
|
||
|
||
if the return object or provider holds the last reference to its shared state,
|
||
the shared state is destroyed; and
|
||
|
||
- [(5.2)](#state-5.2)
|
||
|
||
the return object or provider gives up its reference to its shared state; and
|
||
|
||
- [(5.3)](#state-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 tostd::async, the shared state is not yet ready, and this was the last reference
|
||
to the shared state[.](#state-5.sentence-1)
|
||
|
||
[6](#state-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11363)
|
||
|
||
When an asynchronous provider is said to make its shared state ready, it means:
|
||
|
||
- [(6.1)](#state-6.1)
|
||
|
||
first, the provider marks its shared state as ready; and
|
||
|
||
- [(6.2)](#state-6.2)
|
||
|
||
second, the provider unblocks any execution agents waiting for its shared
|
||
state to become ready[.](#state-6.sentence-1)
|
||
|
||
[7](#state-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11373)
|
||
|
||
When an asynchronous provider is said to abandon its shared state, it means:
|
||
|
||
- [(7.1)](#state-7.1)
|
||
|
||
first, if that state is not ready, the provider
|
||
* [(7.1.1)](#state-7.1.1)
|
||
|
||
stores an exception object of type future_error with an error condition ofbroken_promise within its shared state; and then
|
||
|
||
* [(7.1.2)](#state-7.1.2)
|
||
|
||
makes its shared state ready;
|
||
|
||
- [(7.2)](#state-7.2)
|
||
|
||
second, the provider releases its shared state[.](#state-7.sentence-1)
|
||
|
||
[8](#state-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11389)
|
||
|
||
A shared state is [*ready*](#def:ready "32.10.5 Shared state [futures.state]") only if it holds a value or an exception ready for
|
||
retrieval[.](#state-8.sentence-1)
|
||
|
||
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[.](#state-8.sentence-2)
|
||
|
||
[9](#state-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11396)
|
||
|
||
Calls to functions that successfully set the stored result of a shared
|
||
state [synchronize with](intro.multithread#def:synchronize_with "6.10.2 Multi-threaded executions and data races [intro.multithread]") calls to functions
|
||
successfully detecting the ready state resulting from that setting[.](#state-9.sentence-1)
|
||
|
||
The storage of the result
|
||
(whether normal or exceptional) into the shared state[synchronizes with](intro.multithread#def:synchronize_with "6.10.2 Multi-threaded executions and data races [intro.multithread]") the successful return from a call to a waiting function on the shared state[.](#state-9.sentence-2)
|
||
|
||
[10](#state-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11405)
|
||
|
||
Some functions (e.g., promise::set_value_at_thread_exit) delay making
|
||
the shared state ready until the calling thread exits[.](#state-10.sentence-1)
|
||
|
||
The destruction of
|
||
each of that thread's objects with [thread storage duration](basic.stc.thread "6.8.6.3 Thread storage duration [basic.stc.thread]") is sequenced before making that shared state ready[.](#state-10.sentence-2)
|
||
|
||
[11](#state-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11411)
|
||
|
||
Access to the result of the same shared state may [conflict](intro.multithread#def:conflict "6.10.2 Multi-threaded executions and data races [intro.multithread]")[.](#state-11.sentence-1)
|
||
|
||
[*Note [3](#state-note-3)*:
|
||
|
||
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]](res.on.data.races "16.4.6.10 Data race avoidance"))[.](#state-11.sentence-2)
|
||
|
||
For example, concurrent accesses through
|
||
references returned by shared_future::get() ([[futures.shared.future]](#shared.future "32.10.8 Class template shared_future"))
|
||
must either use read-only operations or provide additional synchronization[.](#state-11.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
### [32.10.6](#promise) Class template promise [[futures.promise]](futures.promise)
|
||
|
||
[ð](#lib:promise)
|
||
|
||
namespace std {template<class R>class promise {public: promise(); template<class Allocator> promise(allocator_arg_t, const Allocator& a);
|
||
promise(promise&& rhs) noexcept;
|
||
promise(const promise&) = delete; ~promise(); // assignment promise& operator=(promise&& rhs) noexcept;
|
||
promise& operator=(const promise&) = delete; void swap(promise& other) noexcept; // retrieving the result future<R> get_future(); // setting the resultvoid set_value(*see below*); void set_exception(exception_ptr p); // setting the result with deferred notificationvoid set_value_at_thread_exit(*see below*); void set_exception_at_thread_exit(exception_ptr p); };}
|
||
|
||
[1](#promise-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11455)
|
||
|
||
For the primary template, R shall be an object type that
|
||
meets the [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2 Template argument requirements [utility.arg.requirements]") requirements[.](#promise-1.sentence-1)
|
||
|
||
[2](#promise-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11459)
|
||
|
||
The implementation provides the template promise and two specializations,promise<R&> and promise<void>[.](#promise-2.sentence-1)
|
||
|
||
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[.](#promise-2.sentence-2)
|
||
|
||
[3](#promise-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11465)
|
||
|
||
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[.](#promise-3.sentence-1)
|
||
|
||
[ð](#lib:promise,constructor)
|
||
|
||
`promise();
|
||
template<class Allocator>
|
||
promise(allocator_arg_t, const Allocator& a);
|
||
`
|
||
|
||
[4](#promise-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11479)
|
||
|
||
*Effects*: Creates a shared state[.](#promise-4.sentence-1)
|
||
|
||
The second
|
||
constructor uses the allocator a to allocate memory for the shared
|
||
state[.](#promise-4.sentence-2)
|
||
|
||
[ð](#lib:promise,constructor_)
|
||
|
||
`promise(promise&& rhs) noexcept;
|
||
`
|
||
|
||
[5](#promise-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11492)
|
||
|
||
*Effects*: Transfers ownership of the shared state
|
||
of rhs (if any) to the newly-constructed object[.](#promise-5.sentence-1)
|
||
|
||
[6](#promise-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11497)
|
||
|
||
*Postconditions*: rhs has no shared state[.](#promise-6.sentence-1)
|
||
|
||
[ð](#lib:promise,destructor)
|
||
|
||
`~promise();
|
||
`
|
||
|
||
[7](#promise-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11508)
|
||
|
||
*Effects*: Abandons any shared state ([[futures.state]](#state "32.10.5 Shared state"))[.](#promise-7.sentence-1)
|
||
|
||
[ð](#lib:operator=,promise)
|
||
|
||
`promise& operator=(promise&& rhs) noexcept;
|
||
`
|
||
|
||
[8](#promise-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11519)
|
||
|
||
*Effects*: Abandons any shared state ([[futures.state]](#state "32.10.5 Shared state")) and then as ifpromise(std::move(rhs)).swap(*this)[.](#promise-8.sentence-1)
|
||
|
||
[9](#promise-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11524)
|
||
|
||
*Returns*: *this[.](#promise-9.sentence-1)
|
||
|
||
[ð](#lib:swap,promise)
|
||
|
||
`void swap(promise& other) noexcept;
|
||
`
|
||
|
||
[10](#promise-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11535)
|
||
|
||
*Effects*: Exchanges the shared state of *this and other[.](#promise-10.sentence-1)
|
||
|
||
[11](#promise-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11539)
|
||
|
||
*Postconditions*: *this has the shared state (if any) that other had
|
||
prior to the call to swap[.](#promise-11.sentence-1)
|
||
|
||
other has the shared state (if any) that*this had prior to the call to swap[.](#promise-11.sentence-2)
|
||
|
||
[ð](#lib:get_future,promise)
|
||
|
||
`future<R> get_future();
|
||
`
|
||
|
||
[12](#promise-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11552)
|
||
|
||
*Synchronization*: Calls to this function do not introduce
|
||
data races ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races")) with calls toset_value,set_exception,set_value_at_thread_exit, orset_exception_at_thread_exit[.](#promise-12.sentence-1)
|
||
|
||
[*Note [1](#promise-note-1)*:
|
||
|
||
Such calls need not synchronize with each other[.](#promise-12.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[13](#promise-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11564)
|
||
|
||
*Returns*: A future<R> object with the same shared state as*this[.](#promise-13.sentence-1)
|
||
|
||
[14](#promise-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11569)
|
||
|
||
*Throws*: future_error if *this has no shared state or ifget_future has already been called on a promise with the same
|
||
shared state as *this[.](#promise-14.sentence-1)
|
||
|
||
[15](#promise-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11575)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(15.1)](#promise-15.1)
|
||
|
||
future_already_retrieved if get_future has already been called on
|
||
a promise with the same shared state as *this[.](#promise-15.1.sentence-1)
|
||
|
||
- [(15.2)](#promise-15.2)
|
||
|
||
no_state if *this has no shared state[.](#promise-15.2.sentence-1)
|
||
|
||
[ð](#lib:set_value,promise)
|
||
|
||
`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();
|
||
`
|
||
|
||
[16](#promise-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11594)
|
||
|
||
*Effects*: Atomically stores the value r in the shared state and
|
||
makes that state ready ([[futures.state]](#state "32.10.5 Shared state"))[.](#promise-16.sentence-1)
|
||
|
||
[17](#promise-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11599)
|
||
|
||
*Throws*:
|
||
|
||
- [(17.1)](#promise-17.1)
|
||
|
||
future_error if its shared state
|
||
already has a stored value or exception, or
|
||
|
||
- [(17.2)](#promise-17.2)
|
||
|
||
for the first version, any exception thrown by the constructor selected to copy an object of R, or
|
||
|
||
- [(17.3)](#promise-17.3)
|
||
|
||
for the second version, any exception thrown by the constructor selected to move an object of R[.](#promise-17.sentence-1)
|
||
|
||
[18](#promise-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11608)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(18.1)](#promise-18.1)
|
||
|
||
promise_already_satisfied if its shared state
|
||
already has a stored value or exception[.](#promise-18.1.sentence-1)
|
||
|
||
- [(18.2)](#promise-18.2)
|
||
|
||
no_state if *this has no shared state[.](#promise-18.2.sentence-1)
|
||
|
||
[ð](#lib:set_exception,promise)
|
||
|
||
`void set_exception(exception_ptr p);
|
||
`
|
||
|
||
[19](#promise-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11623)
|
||
|
||
*Preconditions*: p is not null[.](#promise-19.sentence-1)
|
||
|
||
[20](#promise-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11627)
|
||
|
||
*Effects*: Atomically stores the exception pointer p in the shared state
|
||
and makes that state ready ([[futures.state]](#state "32.10.5 Shared state"))[.](#promise-20.sentence-1)
|
||
|
||
[21](#promise-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11632)
|
||
|
||
*Throws*: future_error if its shared state
|
||
already has a stored value or exception[.](#promise-21.sentence-1)
|
||
|
||
[22](#promise-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11637)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(22.1)](#promise-22.1)
|
||
|
||
promise_already_satisfied if its shared state
|
||
already has a stored value or exception[.](#promise-22.1.sentence-1)
|
||
|
||
- [(22.2)](#promise-22.2)
|
||
|
||
no_state if *this has no shared state[.](#promise-22.2.sentence-1)
|
||
|
||
[ð](#lib:set_value_at_thread_exit,promise)
|
||
|
||
`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();
|
||
`
|
||
|
||
[23](#promise-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11655)
|
||
|
||
*Effects*: Stores the value r in the shared state without making that
|
||
state ready immediately[.](#promise-23.sentence-1)
|
||
|
||
Schedules that state to be made ready when the current
|
||
thread exits, after all objects with thread storage duration associated with the
|
||
current thread have been destroyed[.](#promise-23.sentence-2)
|
||
|
||
[24](#promise-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11662)
|
||
|
||
*Throws*:
|
||
|
||
- [(24.1)](#promise-24.1)
|
||
|
||
future_error if its shared state
|
||
already has a stored value or exception, or
|
||
|
||
- [(24.2)](#promise-24.2)
|
||
|
||
for the first version, any exception thrown by the constructor selected to copy an object of R, or
|
||
|
||
- [(24.3)](#promise-24.3)
|
||
|
||
for the second version, any exception thrown by the constructor selected to move an object of R[.](#promise-24.sentence-1)
|
||
|
||
[25](#promise-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11671)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(25.1)](#promise-25.1)
|
||
|
||
promise_already_satisfied if its shared state
|
||
already has a stored value or exception[.](#promise-25.1.sentence-1)
|
||
|
||
- [(25.2)](#promise-25.2)
|
||
|
||
no_state if *this has no shared state[.](#promise-25.2.sentence-1)
|
||
|
||
[ð](#lib:set_exception_at_thread_exit,promise)
|
||
|
||
`void set_exception_at_thread_exit(exception_ptr p);
|
||
`
|
||
|
||
[26](#promise-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11686)
|
||
|
||
*Preconditions*: p is not null[.](#promise-26.sentence-1)
|
||
|
||
[27](#promise-27)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11690)
|
||
|
||
*Effects*: Stores the exception pointer p in the shared state without
|
||
making that state ready immediately[.](#promise-27.sentence-1)
|
||
|
||
Schedules that state to be made ready when
|
||
the current thread exits, after all objects with thread storage duration
|
||
associated with the current thread have been destroyed[.](#promise-27.sentence-2)
|
||
|
||
[28](#promise-28)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11697)
|
||
|
||
*Throws*: future_error if an error condition occurs[.](#promise-28.sentence-1)
|
||
|
||
[29](#promise-29)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11701)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(29.1)](#promise-29.1)
|
||
|
||
promise_already_satisfied if its shared state
|
||
already has a stored value or exception[.](#promise-29.1.sentence-1)
|
||
|
||
- [(29.2)](#promise-29.2)
|
||
|
||
no_state if *this has no shared state[.](#promise-29.2.sentence-1)
|
||
|
||
[ð](#lib:swap,promise_)
|
||
|
||
`template<class R>
|
||
void swap(promise<R>& x, promise<R>& y) noexcept;
|
||
`
|
||
|
||
[30](#promise-30)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11717)
|
||
|
||
*Effects*: As if by x.swap(y)[.](#promise-30.sentence-1)
|
||
|
||
### [32.10.7](#unique.future) Class template future [[futures.unique.future]](futures.unique.future)
|
||
|
||
[1](#unique.future-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11724)
|
||
|
||
The class template future defines a type for asynchronous return objects which
|
||
do not share their shared state with other asynchronous return objects[.](#unique.future-1.sentence-1)
|
||
|
||
A default-constructed future object has no
|
||
shared state[.](#unique.future-1.sentence-2)
|
||
|
||
A future object with shared state can be created by
|
||
functions on [asynchronous providers](#def:asynchronous_provider "32.10.5 Shared state [futures.state]") or by the move constructor and shares its shared state with
|
||
the original asynchronous provider[.](#unique.future-1.sentence-3)
|
||
|
||
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[.](#unique.future-1.sentence-4)
|
||
|
||
[2](#unique.future-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11739)
|
||
|
||
[*Note [1](#unique.future-note-1)*:
|
||
|
||
Member functions of future do not synchronize with themselves or with
|
||
member functions of shared_future[.](#unique.future-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[3](#unique.future-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11745)
|
||
|
||
The effect of calling any member function other than the destructor, the
|
||
move assignment operator, share, or valid on a future object for whichvalid() == false is undefined[.](#unique.future-3.sentence-1)
|
||
|
||
[*Note [2](#unique.future-note-2)*:
|
||
|
||
It is valid to move from a future object for which valid() == false[.](#unique.future-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
*Recommended practice*: Implementations should detect this case and throw an object of typefuture_error with an error condition of future_errc::no_state[.](#unique.future-3.sentence-3)
|
||
|
||
[ð](#lib:future)
|
||
|
||
namespace std {template<class R>class future {public: future() noexcept;
|
||
future(future&&) noexcept;
|
||
future(const future&) = delete; ~future();
|
||
future& operator=(const future&) = delete;
|
||
future& operator=(future&&) noexcept;
|
||
shared_future<R> share() noexcept; // retrieving the value*see below* get(); // functions to check statebool 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](#unique.future-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11787)
|
||
|
||
For the primary template, R shall be an object type that
|
||
meets the [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2 Template argument requirements [utility.arg.requirements]") requirements[.](#unique.future-4.sentence-1)
|
||
|
||
[5](#unique.future-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11791)
|
||
|
||
The implementation provides the template future and two specializations,future<R&> and future<void>[.](#unique.future-5.sentence-1)
|
||
|
||
These differ only in the return type and return
|
||
value of the member function get, as set out in its description, below[.](#unique.future-5.sentence-2)
|
||
|
||
[ð](#lib:future,constructor)
|
||
|
||
`future() noexcept;
|
||
`
|
||
|
||
[6](#unique.future-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11802)
|
||
|
||
*Effects*: The object does not refer to a shared state[.](#unique.future-6.sentence-1)
|
||
|
||
[7](#unique.future-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11806)
|
||
|
||
*Postconditions*: valid() == false[.](#unique.future-7.sentence-1)
|
||
|
||
[ð](#lib:future,constructor_)
|
||
|
||
`future(future&& rhs) noexcept;
|
||
`
|
||
|
||
[8](#unique.future-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11817)
|
||
|
||
*Effects*: Move constructs a future object that refers to the shared
|
||
state that
|
||
was originally referred to by rhs (if any)[.](#unique.future-8.sentence-1)
|
||
|
||
[9](#unique.future-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11823)
|
||
|
||
*Postconditions*:
|
||
|
||
- [(9.1)](#unique.future-9.1)
|
||
|
||
valid() returns the same value as rhs.valid() prior to the
|
||
constructor invocation[.](#unique.future-9.1.sentence-1)
|
||
|
||
- [(9.2)](#unique.future-9.2)
|
||
|
||
rhs.valid() == false[.](#unique.future-9.2.sentence-1)
|
||
|
||
[ð](#lib:future,constructor__)
|
||
|
||
`~future();
|
||
`
|
||
|
||
[10](#unique.future-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11838)
|
||
|
||
*Effects*:
|
||
|
||
- [(10.1)](#unique.future-10.1)
|
||
|
||
Releases any shared state ([[futures.state]](#state "32.10.5 Shared state"));
|
||
|
||
- [(10.2)](#unique.future-10.2)
|
||
|
||
destroys *this[.](#unique.future-10.sentence-1)
|
||
|
||
[ð](#lib:operator=,future)
|
||
|
||
`future& operator=(future&& rhs) noexcept;
|
||
`
|
||
|
||
[11](#unique.future-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11854)
|
||
|
||
*Effects*: If addressof(rhs) == this is true, there are no effects[.](#unique.future-11.sentence-1)
|
||
|
||
Otherwise:
|
||
|
||
- [(11.1)](#unique.future-11.1)
|
||
|
||
Releases any shared state ([[futures.state]](#state "32.10.5 Shared state"))[.](#unique.future-11.1.sentence-1)
|
||
|
||
- [(11.2)](#unique.future-11.2)
|
||
|
||
move assigns the contents of rhs to *this[.](#unique.future-11.2.sentence-1)
|
||
|
||
[12](#unique.future-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11865)
|
||
|
||
*Postconditions*:
|
||
|
||
- [(12.1)](#unique.future-12.1)
|
||
|
||
valid() returns the same value as rhs.valid() prior to the
|
||
assignment[.](#unique.future-12.1.sentence-1)
|
||
|
||
- [(12.2)](#unique.future-12.2)
|
||
|
||
If addressof(rhs) == this is false,rhs.valid() == false[.](#unique.future-12.2.sentence-1)
|
||
|
||
[ð](#lib:share,future)
|
||
|
||
`shared_future<R> share() noexcept;
|
||
`
|
||
|
||
[13](#unique.future-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11884)
|
||
|
||
*Postconditions*: valid() == false[.](#unique.future-13.sentence-1)
|
||
|
||
[14](#unique.future-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11888)
|
||
|
||
*Returns*: shared_future<R>(std::move(*this))[.](#unique.future-14.sentence-1)
|
||
|
||
[ð](#lib:get,future)
|
||
|
||
`R future::get();
|
||
R& future<R&>::get();
|
||
void future<void>::get();
|
||
`
|
||
|
||
[15](#unique.future-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11901)
|
||
|
||
[*Note [3](#unique.future-note-3)*:
|
||
|
||
As described above, the template and its two required specializations differ only in
|
||
the return type and return value of the member function get[.](#unique.future-15.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[16](#unique.future-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11907)
|
||
|
||
*Effects*:
|
||
|
||
- [(16.1)](#unique.future-16.1)
|
||
|
||
wait()s until the shared state is ready, then retrieves the
|
||
value stored in the shared state;
|
||
|
||
- [(16.2)](#unique.future-16.2)
|
||
|
||
releases any shared state ([[futures.state]](#state "32.10.5 Shared state"))[.](#unique.future-16.sentence-1)
|
||
|
||
[17](#unique.future-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11915)
|
||
|
||
*Postconditions*: valid() == false[.](#unique.future-17.sentence-1)
|
||
|
||
[18](#unique.future-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11919)
|
||
|
||
*Returns*:
|
||
|
||
- [(18.1)](#unique.future-18.1)
|
||
|
||
future::get() returns the value v stored in the object's shared state asstd::move(v)[.](#unique.future-18.1.sentence-1)
|
||
|
||
- [(18.2)](#unique.future-18.2)
|
||
|
||
future<R&>::get() returns the reference stored as value in the object's shared state[.](#unique.future-18.2.sentence-1)
|
||
|
||
- [(18.3)](#unique.future-18.3)
|
||
|
||
future<void>::get() returns nothing[.](#unique.future-18.3.sentence-1)
|
||
|
||
[19](#unique.future-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11933)
|
||
|
||
*Throws*: The stored exception, if an exception was stored in the shared state[.](#unique.future-19.sentence-1)
|
||
|
||
[ð](#lib:valid,future)
|
||
|
||
`bool valid() const noexcept;
|
||
`
|
||
|
||
[20](#unique.future-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11944)
|
||
|
||
*Returns*: true only if *this refers to a shared state[.](#unique.future-20.sentence-1)
|
||
|
||
[ð](#lib:wait,future)
|
||
|
||
`void wait() const;
|
||
`
|
||
|
||
[21](#unique.future-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11955)
|
||
|
||
*Effects*: Blocks until the shared state is ready[.](#unique.future-21.sentence-1)
|
||
|
||
[ð](#lib:wait_for,future)
|
||
|
||
`template<class Rep, class Period>
|
||
future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
|
||
`
|
||
|
||
[22](#unique.future-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11968)
|
||
|
||
*Effects*: None if the shared state contains a deferred function ([[futures.async]](#async "32.10.9 Function template async")),
|
||
otherwise
|
||
blocks until the shared state is ready or until
|
||
the relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by rel_time has expired[.](#unique.future-22.sentence-1)
|
||
|
||
[23](#unique.future-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11976)
|
||
|
||
*Returns*:
|
||
|
||
- [(23.1)](#unique.future-23.1)
|
||
|
||
future_status::deferred if the shared state contains a deferred
|
||
function[.](#unique.future-23.1.sentence-1)
|
||
|
||
- [(23.2)](#unique.future-23.2)
|
||
|
||
future_status::ready if the shared state is ready[.](#unique.future-23.2.sentence-1)
|
||
|
||
- [(23.3)](#unique.future-23.3)
|
||
|
||
future_status::timeout if the function is returning because the
|
||
relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))
|
||
specified by rel_time has expired[.](#unique.future-23.3.sentence-1)
|
||
|
||
[24](#unique.future-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11989)
|
||
|
||
*Throws*: timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#unique.future-24.sentence-1)
|
||
|
||
[ð](#lib:wait_until,future)
|
||
|
||
`template<class Clock, class Duration>
|
||
future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
|
||
`
|
||
|
||
[25](#unique.future-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12001)
|
||
|
||
*Effects*: None if the shared state contains a deferred function ([[futures.async]](#async "32.10.9 Function template async")),
|
||
otherwise
|
||
blocks until the shared state is ready or until
|
||
the absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified by abs_time has expired[.](#unique.future-25.sentence-1)
|
||
|
||
[26](#unique.future-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12009)
|
||
|
||
*Returns*:
|
||
|
||
- [(26.1)](#unique.future-26.1)
|
||
|
||
future_status::deferred if the shared state contains a deferred
|
||
function[.](#unique.future-26.1.sentence-1)
|
||
|
||
- [(26.2)](#unique.future-26.2)
|
||
|
||
future_status::ready if the shared state is ready[.](#unique.future-26.2.sentence-1)
|
||
|
||
- [(26.3)](#unique.future-26.3)
|
||
|
||
future_status::timeout if the function is returning because the
|
||
absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))
|
||
specified by abs_time has expired[.](#unique.future-26.3.sentence-1)
|
||
|
||
[27](#unique.future-27)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12023)
|
||
|
||
*Throws*: timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#unique.future-27.sentence-1)
|
||
|
||
### [32.10.8](#shared.future) Class template shared_future [[futures.shared.future]](futures.shared.future)
|
||
|
||
[1](#shared.future-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12031)
|
||
|
||
The class template shared_future defines a type for asynchronous return objects
|
||
which may share their shared state with other asynchronous return
|
||
objects[.](#shared.future-1.sentence-1)
|
||
|
||
A default-constructed shared_future object has no shared state[.](#shared.future-1.sentence-2)
|
||
|
||
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](#def:asynchronous_provider "32.10.5 Shared state [futures.state]") of the shared state[.](#shared.future-1.sentence-3)
|
||
|
||
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[.](#shared.future-1.sentence-4)
|
||
|
||
[2](#shared.future-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12045)
|
||
|
||
[*Note [1](#shared.future-note-1)*:
|
||
|
||
Member functions of shared_future do not synchronize with themselves,
|
||
but they synchronize with the shared state[.](#shared.future-2.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[3](#shared.future-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12051)
|
||
|
||
The effect of calling any member function other than the destructor,
|
||
the move assignment operator, the copy assignment operator, orvalid() on a shared_future object for which valid() == false is undefined[.](#shared.future-3.sentence-1)
|
||
|
||
[*Note [2](#shared.future-note-2)*:
|
||
|
||
It is valid to copy or move from a shared_future object for which valid() is false[.](#shared.future-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
*Recommended practice*: Implementations should detect this case and throw an object of typefuture_error with an error condition of future_errc::no_state[.](#shared.future-3.sentence-3)
|
||
|
||
[ð](#lib:shared_future)
|
||
|
||
namespace std {template<class R>class shared_future {public: shared_future() noexcept;
|
||
shared_future(const shared_future& rhs) noexcept;
|
||
shared_future(future<R>&&) noexcept;
|
||
shared_future(shared_future&& rhs) noexcept; ~shared_future();
|
||
shared_future& operator=(const shared_future& rhs) noexcept;
|
||
shared_future& operator=(shared_future&& rhs) noexcept; // retrieving the value*see below* get() const; // functions to check statebool 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](#shared.future-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12093)
|
||
|
||
For the primary template, R shall be an object type that
|
||
meets the [*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2 Template argument requirements [utility.arg.requirements]") requirements[.](#shared.future-4.sentence-1)
|
||
|
||
[5](#shared.future-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12097)
|
||
|
||
The implementation provides the template shared_future and two
|
||
specializations, shared_future<R&> and shared_future<void>[.](#shared.future-5.sentence-1)
|
||
|
||
These
|
||
differ only in the return type and return value of the member function get, as
|
||
set out in its description, below[.](#shared.future-5.sentence-2)
|
||
|
||
[ð](#lib:shared_future,constructor)
|
||
|
||
`shared_future() noexcept;
|
||
`
|
||
|
||
[6](#shared.future-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12109)
|
||
|
||
*Effects*: The object does not refer to a shared state[.](#shared.future-6.sentence-1)
|
||
|
||
[7](#shared.future-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12113)
|
||
|
||
*Postconditions*: valid() == false[.](#shared.future-7.sentence-1)
|
||
|
||
[ð](#lib:shared_future,constructor_)
|
||
|
||
`shared_future(const shared_future& rhs) noexcept;
|
||
`
|
||
|
||
[8](#shared.future-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12124)
|
||
|
||
*Effects*: The object refers to the same
|
||
shared state as rhs (if any)[.](#shared.future-8.sentence-1)
|
||
|
||
[9](#shared.future-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12129)
|
||
|
||
*Postconditions*: valid() returns the same value as rhs.valid()[.](#shared.future-9.sentence-1)
|
||
|
||
[ð](#lib:shared_future,constructor__)
|
||
|
||
`shared_future(future<R>&& rhs) noexcept;
|
||
shared_future(shared_future&& rhs) noexcept;
|
||
`
|
||
|
||
[10](#shared.future-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12141)
|
||
|
||
*Effects*: Move constructs a shared_future object that refers to the
|
||
shared state that was originally referred to by rhs (if any)[.](#shared.future-10.sentence-1)
|
||
|
||
[11](#shared.future-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12146)
|
||
|
||
*Postconditions*:
|
||
|
||
- [(11.1)](#shared.future-11.1)
|
||
|
||
valid() returns the same value as rhs.valid() returned prior to
|
||
the constructor invocation[.](#shared.future-11.1.sentence-1)
|
||
|
||
- [(11.2)](#shared.future-11.2)
|
||
|
||
rhs.valid() == false[.](#shared.future-11.2.sentence-1)
|
||
|
||
[ð](#lib:shared_future,destructor)
|
||
|
||
`~shared_future();
|
||
`
|
||
|
||
[12](#shared.future-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12161)
|
||
|
||
*Effects*:
|
||
|
||
- [(12.1)](#shared.future-12.1)
|
||
|
||
Releases any shared state ([[futures.state]](#state "32.10.5 Shared state"));
|
||
|
||
- [(12.2)](#shared.future-12.2)
|
||
|
||
destroys *this[.](#shared.future-12.sentence-1)
|
||
|
||
[ð](#lib:operator=,shared_future)
|
||
|
||
`shared_future& operator=(shared_future&& rhs) noexcept;
|
||
`
|
||
|
||
[13](#shared.future-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12177)
|
||
|
||
*Effects*: If addressof(rhs) == this is true, there are no effects[.](#shared.future-13.sentence-1)
|
||
|
||
Otherwise:
|
||
|
||
- [(13.1)](#shared.future-13.1)
|
||
|
||
Releases any shared state ([[futures.state]](#state "32.10.5 Shared state"));
|
||
|
||
- [(13.2)](#shared.future-13.2)
|
||
|
||
move assigns the contents of rhs to *this[.](#shared.future-13.sentence-2)
|
||
|
||
[14](#shared.future-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12188)
|
||
|
||
*Postconditions*:
|
||
|
||
- [(14.1)](#shared.future-14.1)
|
||
|
||
valid() returns the same value as rhs.valid() returned prior to
|
||
the assignment[.](#shared.future-14.1.sentence-1)
|
||
|
||
- [(14.2)](#shared.future-14.2)
|
||
|
||
If addressof(rhs) == this is false,rhs.valid() == false[.](#shared.future-14.2.sentence-1)
|
||
|
||
[ð](#lib:operator=,shared_future_)
|
||
|
||
`shared_future& operator=(const shared_future& rhs) noexcept;
|
||
`
|
||
|
||
[15](#shared.future-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12207)
|
||
|
||
*Effects*: If addressof(rhs) == this is true, there are no effects[.](#shared.future-15.sentence-1)
|
||
|
||
Otherwise:
|
||
|
||
- [(15.1)](#shared.future-15.1)
|
||
|
||
Releases any shared state ([[futures.state]](#state "32.10.5 Shared state"));
|
||
|
||
- [(15.2)](#shared.future-15.2)
|
||
|
||
assigns the contents of rhs to *this[.](#shared.future-15.sentence-2)
|
||
[*Note [3](#shared.future-note-3)*:
|
||
As a result,*this refers to the same shared state as rhs (if any)[.](#shared.future-15.2.sentence-2)
|
||
â *end note*]
|
||
|
||
[16](#shared.future-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12223)
|
||
|
||
*Postconditions*: valid() == rhs.valid()[.](#shared.future-16.sentence-1)
|
||
|
||
[ð](#lib:get,shared_future)
|
||
|
||
`const R& shared_future::get() const;
|
||
R& shared_future<R&>::get() const;
|
||
void shared_future<void>::get() const;
|
||
`
|
||
|
||
[17](#shared.future-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12236)
|
||
|
||
[*Note [4](#shared.future-note-4)*:
|
||
|
||
As described above, the template and its two required specializations differ only in
|
||
the return type and return value of the member function get[.](#shared.future-17.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[18](#shared.future-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12242)
|
||
|
||
[*Note [5](#shared.future-note-5)*:
|
||
|
||
Access to a value object stored in the shared state is
|
||
unsynchronized, so operations on R might
|
||
introduce a data race ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))[.](#shared.future-18.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[19](#shared.future-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12249)
|
||
|
||
*Effects*: wait()s until the shared state is ready, then retrieves the
|
||
value stored in the shared state[.](#shared.future-19.sentence-1)
|
||
|
||
[20](#shared.future-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12254)
|
||
|
||
*Returns*:
|
||
|
||
- [(20.1)](#shared.future-20.1)
|
||
|
||
shared_future::get() returns a const reference to the value stored in the object's
|
||
shared state[.](#shared.future-20.1.sentence-1)
|
||
[*Note [6](#shared.future-note-6)*:
|
||
Access through that reference after the shared state has been
|
||
destroyed produces undefined behavior; this can be avoided by not storing the reference in any
|
||
storage with a greater lifetime than the shared_future object that returned the
|
||
reference[.](#shared.future-20.1.sentence-2)
|
||
â *end note*]
|
||
|
||
- [(20.2)](#shared.future-20.2)
|
||
|
||
shared_future<R&>::get() returns the reference stored as value in the object's
|
||
shared state[.](#shared.future-20.2.sentence-1)
|
||
|
||
- [(20.3)](#shared.future-20.3)
|
||
|
||
shared_future<void>::get() returns nothing[.](#shared.future-20.3.sentence-1)
|
||
|
||
[21](#shared.future-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12275)
|
||
|
||
*Throws*: The stored exception, if an exception was stored in the shared state[.](#shared.future-21.sentence-1)
|
||
|
||
[ð](#lib:valid,shared_future)
|
||
|
||
`bool valid() const noexcept;
|
||
`
|
||
|
||
[22](#shared.future-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12286)
|
||
|
||
*Returns*: true only if *this refers to a shared state[.](#shared.future-22.sentence-1)
|
||
|
||
[ð](#lib:wait,shared_future)
|
||
|
||
`void wait() const;
|
||
`
|
||
|
||
[23](#shared.future-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12297)
|
||
|
||
*Effects*: Blocks until the shared state is ready[.](#shared.future-23.sentence-1)
|
||
|
||
[ð](#lib:wait_for,shared_future)
|
||
|
||
`template<class Rep, class Period>
|
||
future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
|
||
`
|
||
|
||
[24](#shared.future-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12310)
|
||
|
||
*Effects*: None if the shared state contains a deferred function ([[futures.async]](#async "32.10.9 Function template async")),
|
||
otherwise
|
||
blocks until the shared state is ready or until
|
||
the relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified byrel_time has expired[.](#shared.future-24.sentence-1)
|
||
|
||
[25](#shared.future-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12319)
|
||
|
||
*Returns*:
|
||
|
||
- [(25.1)](#shared.future-25.1)
|
||
|
||
future_status::deferred if the shared state contains a deferred
|
||
function[.](#shared.future-25.1.sentence-1)
|
||
|
||
- [(25.2)](#shared.future-25.2)
|
||
|
||
future_status::ready if the shared state is ready[.](#shared.future-25.2.sentence-1)
|
||
|
||
- [(25.3)](#shared.future-25.3)
|
||
|
||
future_status::timeout if the function is returning because the
|
||
relative timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))
|
||
specified by rel_time has expired[.](#shared.future-25.3.sentence-1)
|
||
|
||
[26](#shared.future-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12332)
|
||
|
||
*Throws*: timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#shared.future-26.sentence-1)
|
||
|
||
[ð](#lib:wait_until,shared_future)
|
||
|
||
`template<class Clock, class Duration>
|
||
future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
|
||
`
|
||
|
||
[27](#shared.future-27)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12344)
|
||
|
||
*Effects*: None if the shared state contains a deferred function ([[futures.async]](#async "32.10.9 Function template async")),
|
||
otherwise
|
||
blocks until the shared state is ready or until the
|
||
absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications")) specified byabs_time has expired[.](#shared.future-27.sentence-1)
|
||
|
||
[28](#shared.future-28)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12353)
|
||
|
||
*Returns*:
|
||
|
||
- [(28.1)](#shared.future-28.1)
|
||
|
||
future_status::deferred if the shared state contains a deferred
|
||
function[.](#shared.future-28.1.sentence-1)
|
||
|
||
- [(28.2)](#shared.future-28.2)
|
||
|
||
future_status::ready if the shared state is ready[.](#shared.future-28.2.sentence-1)
|
||
|
||
- [(28.3)](#shared.future-28.3)
|
||
|
||
future_status::timeout if the function is returning because the
|
||
absolute timeout ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))
|
||
specified by abs_time has expired[.](#shared.future-28.3.sentence-1)
|
||
|
||
[29](#shared.future-29)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12366)
|
||
|
||
*Throws*: timeout-related exceptions ([[thread.req.timing]](thread.req.timing "32.2.4 Timing specifications"))[.](#shared.future-29.sentence-1)
|
||
|
||
### [32.10.9](#async) Function template async [[futures.async]](futures.async)
|
||
|
||
[1](#async-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12373)
|
||
|
||
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[.](#async-1.sentence-1)
|
||
|
||
[ð](#lib:async)
|
||
|
||
`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);
|
||
`
|
||
|
||
[2](#async-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12389)
|
||
|
||
*Mandates*: The following are all true:
|
||
|
||
- [(2.1)](#async-2.1)
|
||
|
||
is_constructible_v<decay_t<F>, F>,
|
||
|
||
- [(2.2)](#async-2.2)
|
||
|
||
(is_constructible_v<decay_t<Args>, Args> && ...), and
|
||
|
||
- [(2.3)](#async-2.3)
|
||
|
||
is_invocable_v<decay_t<F>, decay_t<Args>...>[.](#async-2.sentence-1)
|
||
|
||
[3](#async-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12398)
|
||
|
||
*Effects*: The first function
|
||
behaves the same as a call to the second function with a policy argument oflaunch::async | launch::deferred and the same arguments for F and Args[.](#async-3.sentence-1)
|
||
|
||
The second function creates a shared state that is associated with
|
||
the returned future object[.](#async-3.sentence-2)
|
||
|
||
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):
|
||
|
||
- [(3.1)](#async-3.1)
|
||
|
||
If launch::async is set in policy, callsinvoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...) ([[func.invoke]](func.invoke "22.10.5 invoke functions"), [[thread.thread.constr]](thread.thread.constr "32.4.3.3 Constructors"))
|
||
as if in a new thread of execution represented by a thread object
|
||
with the values produced by auto being materialized ([[conv.rval]](conv.rval "7.3.5 Temporary materialization conversion")) in the thread that called async[.](#async-3.1.sentence-1)
|
||
Any return value
|
||
is stored as the result in the
|
||
shared state[.](#async-3.1.sentence-2)
|
||
Any exception propagated from
|
||
the execution ofinvoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...) is stored as the exceptional result in the shared state[.](#async-3.1.sentence-3)
|
||
The thread object is
|
||
stored in the shared state
|
||
and affects the behavior of any asynchronous return objects that
|
||
reference that state[.](#async-3.1.sentence-4)
|
||
|
||
- [(3.2)](#async-3.2)
|
||
|
||
If launch::deferred is set in policy,
|
||
stores auto(std::forward<F>(f)) andauto(std::forward<Args>(args))... in the shared state[.](#async-3.2.sentence-1)
|
||
These copies of f and args constitute
|
||
a [*deferred function*](#def:function,deferred "32.10.9 Function template async [futures.async]")[.](#async-3.2.sentence-2)
|
||
Invocation of the deferred function evaluatesinvoke(std::move(g), std::move(xyz)) where g is the stored value ofauto(std::forward<F>(f)) and xyz is the stored copy ofauto(std::forward<Args>(args))...[.](#async-3.2.sentence-3)
|
||
Any return value is stored
|
||
as the result in the shared state[.](#async-3.2.sentence-4)
|
||
Any exception propagated
|
||
from the execution
|
||
of the deferred function
|
||
is stored as the exceptional result
|
||
in the shared state[.](#async-3.2.sentence-5)
|
||
The shared state is not
|
||
made ready until the function has completed[.](#async-3.2.sentence-6)
|
||
The first call to a
|
||
non-timed waiting function ([[futures.state]](#state "32.10.5 Shared state"))
|
||
on an asynchronous return object referring to
|
||
this shared state invokes the
|
||
deferred function in the thread that called the waiting function[.](#async-3.2.sentence-7)
|
||
Once evaluation of invoke(std::move(g), std::move(xyz)) begins, the function is no longer
|
||
considered deferred[.](#async-3.2.sentence-8)
|
||
*Recommended practice*: If this policy is specified together with other policies, such as when using apolicy value of launch::async | launch::deferred, implementations should defer
|
||
invocation or the selection of the policy when no more concurrency can be effectively
|
||
exploited[.](#async-3.2.sentence-9)
|
||
|
||
- [(3.3)](#async-3.3)
|
||
|
||
If no value is set in the launch policy, or a value is set that is neither specified
|
||
in this document nor by the implementation, the behavior is undefined[.](#async-3.3.sentence-1)
|
||
|
||
[4](#async-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12464)
|
||
|
||
*Synchronization*: The invocation of async synchronizes with the invocation of f[.](#async-4.sentence-1)
|
||
|
||
The completion of the function f is sequenced before
|
||
the shared state is made ready[.](#async-4.sentence-2)
|
||
|
||
[*Note [1](#async-note-1)*:
|
||
|
||
These apply regardless of the provided policy argument, and
|
||
even if the corresponding future object is moved to another thread[.](#async-4.sentence-3)
|
||
|
||
However, it is possible for f not to be called at all,
|
||
in which case its completion never happens[.](#async-4.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
If the implementation chooses the launch::async policy,
|
||
|
||
- [(4.1)](#async-4.1)
|
||
|
||
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]](thread.thread.member "32.4.3.6 Members"));
|
||
|
||
- [(4.2)](#async-4.2)
|
||
|
||
the associated thread completion[synchronizes with](intro.multithread#def:synchronize_with "6.10.2 Multi-threaded executions and data races [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[.](#async-4.sentence-5)
|
||
|
||
[5](#async-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12494)
|
||
|
||
*Returns*: An object of typefuture<invoke_result_t<decay_t<F>, decay_t<Args>...>> that refers
|
||
to the shared state created by this call to async[.](#async-5.sentence-1)
|
||
|
||
[*Note [2](#async-note-2)*:
|
||
|
||
If a future obtained from async is moved outside the local scope,
|
||
the future's destructor can block for the shared state to become ready[.](#async-5.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[6](#async-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12504)
|
||
|
||
*Throws*: system_error if policy == launch::async and the
|
||
implementation is unable to start a new thread, orstd::bad_alloc if memory for the internal data structures
|
||
cannot be allocated[.](#async-6.sentence-1)
|
||
|
||
[7](#async-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12511)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(7.1)](#async-7.1)
|
||
|
||
resource_unavailable_try_again â ifpolicy == launch::async and the system is unable to start a new thread[.](#async-7.sentence-1)
|
||
|
||
[8](#async-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12519)
|
||
|
||
[*Example [1](#async-example-1)*: int work1(int value);int work2(int value);int work(int value) {auto handle = std::async([=]{ return work2(value); }); int tmp = work1(value); return tmp + handle.get(); // #1}
|
||
|
||
[*Note [3](#async-note-3)*:
|
||
|
||
Line #1 might not result in concurrency because
|
||
the async call uses the default policy, which might uselaunch::deferred, in which case the lambda might not be invoked until theget() call; in that case, work1 and work2 are called on the
|
||
same thread and there is no concurrency[.](#async-8.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
â *end example*]
|
||
|
||
### [32.10.10](#task) Class template packaged_task [[futures.task]](futures.task)
|
||
|
||
#### [32.10.10.1](#task.general) General [[futures.task.general]](futures.task.general)
|
||
|
||
[1](#task.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12544)
|
||
|
||
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[.](#task.general-1.sentence-1)
|
||
|
||
[2](#task.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12549)
|
||
|
||
When the packaged_task object is invoked, its stored task is invoked and the
|
||
result (whether normal or exceptional) stored in the shared state[.](#task.general-2.sentence-1)
|
||
|
||
Any futures that
|
||
share the shared state will then be able to access the stored result[.](#task.general-2.sentence-2)
|
||
|
||
[ð](#lib:packaged_task)
|
||
|
||
namespace std {template<class> class packaged_task; // *not defined*template<class R, class... ArgTypes>class packaged_task<R(ArgTypes...)> {public:// construction and destruction packaged_task() noexcept; template<class F>explicit packaged_task(F&& f); template<class F, class Allocator>explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); ~packaged_task(); // no copy packaged_task(const packaged_task&) = delete;
|
||
packaged_task& operator=(const packaged_task&) = delete; // move support packaged_task(packaged_task&& rhs) noexcept;
|
||
packaged_task& operator=(packaged_task&& rhs) noexcept; void swap(packaged_task& other) noexcept; bool valid() const noexcept; // result retrieval future<R> get_future(); // executionvoid operator()(ArgTypes... ); void make_ready_at_thread_exit(ArgTypes...); void reset(); }; template<class R, class... ArgTypes> packaged_task(R (*)(ArgTypes...)) -> packaged_task<R(ArgTypes...)>; template<class F> packaged_task(F) -> packaged_task<*see below*>;}
|
||
|
||
#### [32.10.10.2](#task.members) Member functions [[futures.task.members]](futures.task.members)
|
||
|
||
[ð](#lib:packaged_task,constructor)
|
||
|
||
`packaged_task() noexcept;
|
||
`
|
||
|
||
[1](#task.members-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12606)
|
||
|
||
*Effects*: The object has no shared state and no stored task[.](#task.members-1.sentence-1)
|
||
|
||
[ð](#lib:packaged_task,constructor_)
|
||
|
||
`template<class F>
|
||
explicit packaged_task(F&& f);
|
||
`
|
||
|
||
[2](#task.members-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12618)
|
||
|
||
*Effects*: Equivalent topackaged_task(allocator_arg, allocator<int>(), std::forward<F>(f))[.](#task.members-2.sentence-1)
|
||
|
||
[ð](#lib:packaged_task,constructor__)
|
||
|
||
`template<class F, class Allocator>
|
||
explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f);
|
||
`
|
||
|
||
[3](#task.members-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12631)
|
||
|
||
*Constraints*: remove_cvref_t<F> is not the same type as packaged_task<R(ArgTypes...)>[.](#task.members-3.sentence-1)
|
||
|
||
[4](#task.members-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12636)
|
||
|
||
*Mandates*: is_invocable_r_v<R, decay_t<F>&, ArgTypes...> is true[.](#task.members-4.sentence-1)
|
||
|
||
[5](#task.members-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12640)
|
||
|
||
*Preconditions*: Allocator meets the *Cpp17Allocator* requirements ([[allocator.requirements.general]](allocator.requirements.general "16.4.4.6.1 General"))[.](#task.members-5.sentence-1)
|
||
|
||
[6](#task.members-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12644)
|
||
|
||
*Effects*: Let A2 beallocator_traits<Allocator>::rebind_alloc<*unspecified*> and let a2 be an object of type A2 initialized withA2(a)[.](#task.members-6.sentence-1)
|
||
|
||
Constructs a new packaged_task object with
|
||
a stored task of type decay_t<F> and a shared state[.](#task.members-6.sentence-2)
|
||
|
||
Initializes the object's stored task with std::forward<F>(f)[.](#task.members-6.sentence-3)
|
||
|
||
Uses a2 to allocate storage for the shared state and stores a copy
|
||
of a2 in the shared state[.](#task.members-6.sentence-4)
|
||
|
||
[7](#task.members-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12656)
|
||
|
||
*Throws*: Any exceptions thrown by the initialization of the stored task[.](#task.members-7.sentence-1)
|
||
|
||
If storage for the shared state cannot be allocated, any exception thrown byA2::allocate[.](#task.members-7.sentence-2)
|
||
|
||
[ð](#lib:packaged_task,constructor___)
|
||
|
||
`template<class F> packaged_task(F) -> packaged_task<see below>;
|
||
`
|
||
|
||
[8](#task.members-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12669)
|
||
|
||
*Constraints*: &F::operator() is well-formed when
|
||
treated as an unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3 Context dependence")) and either
|
||
|
||
- [(8.1)](#task.members-8.1)
|
||
|
||
F::operator() is a non-static member function anddecltype(&F::operator()) is either of the formR(G::*)(A...) cv &opt noexceptopt or of the formR(*)(G, A...) noexceptopt for a type G, or
|
||
|
||
- [(8.2)](#task.members-8.2)
|
||
|
||
F::operator() is a static member function anddecltype(&F::operator()) is of the formR(*)(A...) noexceptopt[.](#task.members-8.sentence-1)
|
||
|
||
[9](#task.members-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12687)
|
||
|
||
*Remarks*: The deduced type is packaged_task<R(A...)>[.](#task.members-9.sentence-1)
|
||
|
||
[ð](#lib:packaged_task,constructor____)
|
||
|
||
`packaged_task(packaged_task&& rhs) noexcept;
|
||
`
|
||
|
||
[10](#task.members-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12698)
|
||
|
||
*Effects*: Transfers ownership ofrhs's shared state to *this, leaving rhs with no
|
||
shared state[.](#task.members-10.sentence-1)
|
||
|
||
Moves the stored task from rhs to *this[.](#task.members-10.sentence-2)
|
||
|
||
[11](#task.members-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12704)
|
||
|
||
*Postconditions*: rhs has no shared state[.](#task.members-11.sentence-1)
|
||
|
||
[ð](#lib:operator=,packaged_task)
|
||
|
||
`packaged_task& operator=(packaged_task&& rhs) noexcept;
|
||
`
|
||
|
||
[12](#task.members-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12715)
|
||
|
||
*Effects*:
|
||
|
||
- [(12.1)](#task.members-12.1)
|
||
|
||
Releases any shared state ([[futures.state]](#state "32.10.5 Shared state"));
|
||
|
||
- [(12.2)](#task.members-12.2)
|
||
|
||
calls packaged_task(std::move(rhs)).swap(*this)[.](#task.members-12.sentence-1)
|
||
|
||
[ð](#lib:packaged_task,destructor)
|
||
|
||
`~packaged_task();
|
||
`
|
||
|
||
[13](#task.members-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12731)
|
||
|
||
*Effects*: Abandons any shared state ([[futures.state]](#state "32.10.5 Shared state"))[.](#task.members-13.sentence-1)
|
||
|
||
[ð](#lib:swap,packaged_task)
|
||
|
||
`void swap(packaged_task& other) noexcept;
|
||
`
|
||
|
||
[14](#task.members-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12742)
|
||
|
||
*Effects*: Exchanges the shared states and stored tasks of *this and other[.](#task.members-14.sentence-1)
|
||
|
||
[15](#task.members-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12746)
|
||
|
||
*Postconditions*: *this has the same shared state
|
||
and stored task (if any) as other prior to the call to swap[.](#task.members-15.sentence-1)
|
||
|
||
other has the same shared state
|
||
and stored task (if any)
|
||
as *this prior to the call to swap[.](#task.members-15.sentence-2)
|
||
|
||
[ð](#lib:valid,packaged_task)
|
||
|
||
`bool valid() const noexcept;
|
||
`
|
||
|
||
[16](#task.members-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12761)
|
||
|
||
*Returns*: true only if *this has a shared state[.](#task.members-16.sentence-1)
|
||
|
||
[ð](#lib:get_future,packaged_task)
|
||
|
||
`future<R> get_future();
|
||
`
|
||
|
||
[17](#task.members-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12772)
|
||
|
||
*Synchronization*: Calls to this function do not introduce
|
||
data races ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races")) with calls tooperator() ormake_ready_at_thread_exit[.](#task.members-17.sentence-1)
|
||
|
||
[*Note [1](#task.members-note-1)*:
|
||
|
||
Such calls need not synchronize with each other[.](#task.members-17.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[18](#task.members-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12782)
|
||
|
||
*Returns*: A future object that shares the same shared state as *this[.](#task.members-18.sentence-1)
|
||
|
||
[19](#task.members-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12786)
|
||
|
||
*Throws*: A future_error object if an error occurs[.](#task.members-19.sentence-1)
|
||
|
||
[20](#task.members-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12790)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(20.1)](#task.members-20.1)
|
||
|
||
future_already_retrieved if get_future has already been called on
|
||
a packaged_task object with the same shared state as *this[.](#task.members-20.1.sentence-1)
|
||
|
||
- [(20.2)](#task.members-20.2)
|
||
|
||
no_state if *this has no shared state[.](#task.members-20.2.sentence-1)
|
||
|
||
[ð](#lib:operator(),packaged_task)
|
||
|
||
`void operator()(ArgTypes... args);
|
||
`
|
||
|
||
[21](#task.members-21)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12805)
|
||
|
||
*Effects*: As if by *INVOKE*<R>(f, t1, t2, …, tN) ([[func.require]](func.require "22.10.4 Requirements")),
|
||
where f is the
|
||
stored task of *this andt1, t2, …, tN are the values in args...[.](#task.members-21.sentence-1)
|
||
|
||
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[.](#task.members-21.sentence-2)
|
||
|
||
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[.](#task.members-21.sentence-3)
|
||
|
||
[22](#task.members-22)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12817)
|
||
|
||
*Throws*: A future_error exception object if there is no shared
|
||
state or the stored task has already been invoked[.](#task.members-22.sentence-1)
|
||
|
||
[23](#task.members-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12822)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(23.1)](#task.members-23.1)
|
||
|
||
promise_already_satisfied if
|
||
the stored task has already been invoked[.](#task.members-23.1.sentence-1)
|
||
|
||
- [(23.2)](#task.members-23.2)
|
||
|
||
no_state if *this has no shared state[.](#task.members-23.2.sentence-1)
|
||
|
||
[ð](#lib:make_ready_at_thread_exit,packaged_task)
|
||
|
||
`void make_ready_at_thread_exit(ArgTypes... args);
|
||
`
|
||
|
||
[24](#task.members-24)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12837)
|
||
|
||
*Effects*: As if by *INVOKE*<R>(f, t1, t2, …, tN) ([[func.require]](func.require "22.10.4 Requirements")),
|
||
where f is the stored task andt1, t2, …, tN are the values in args...[.](#task.members-24.sentence-1)
|
||
|
||
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[.](#task.members-24.sentence-2)
|
||
|
||
In either
|
||
case, this is done without making that state ready ([[futures.state]](#state "32.10.5 Shared state")) immediately[.](#task.members-24.sentence-3)
|
||
|
||
Schedules
|
||
the shared state to be made ready when the current thread exits,
|
||
after all objects with thread storage duration associated with the current thread
|
||
have been destroyed[.](#task.members-24.sentence-4)
|
||
|
||
[25](#task.members-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12849)
|
||
|
||
*Throws*: future_error if an error condition occurs[.](#task.members-25.sentence-1)
|
||
|
||
[26](#task.members-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12853)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(26.1)](#task.members-26.1)
|
||
|
||
promise_already_satisfied if the
|
||
stored task has already been invoked[.](#task.members-26.1.sentence-1)
|
||
|
||
- [(26.2)](#task.members-26.2)
|
||
|
||
no_state if *this has no shared state[.](#task.members-26.2.sentence-1)
|
||
|
||
[ð](#lib:reset,packaged_task)
|
||
|
||
`void reset();
|
||
`
|
||
|
||
[27](#task.members-27)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12868)
|
||
|
||
*Effects*: Equivalent to:if (!valid()) {throw future_error(future_errc::no_state);}*this = packaged_task(allocator_arg, a, std::move(f)); wheref is the task stored in*this and a is the allocator stored in the shared state[.](#task.members-27.sentence-1)
|
||
|
||
[*Note [2](#task.members-note-2)*:
|
||
|
||
This constructs a new shared state for *this[.](#task.members-27.sentence-2)
|
||
|
||
The
|
||
old state is abandoned ([[futures.state]](#state "32.10.5 Shared state"))[.](#task.members-27.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[28](#task.members-28)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12885)
|
||
|
||
*Throws*:
|
||
|
||
- [(28.1)](#task.members-28.1)
|
||
|
||
Any exception thrown by the packaged_task constructor[.](#task.members-28.1.sentence-1)
|
||
|
||
- [(28.2)](#task.members-28.2)
|
||
|
||
future_error with an error condition of no_state if *this has no shared state[.](#task.members-28.2.sentence-1)
|
||
|
||
#### [32.10.10.3](#task.nonmembers) Globals [[futures.task.nonmembers]](futures.task.nonmembers)
|
||
|
||
[ð](#lib:swap,packaged_task_)
|
||
|
||
`template<class R, class... ArgTypes>
|
||
void swap(packaged_task<R(ArgTypes...)>& x, packaged_task<R(ArgTypes...)>& y) noexcept;
|
||
`
|
||
|
||
[1](#task.nonmembers-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12903)
|
||
|
||
*Effects*: As if by x.swap(y)[.](#task.nonmembers-1.sentence-1)
|