394 lines
14 KiB
Markdown
394 lines
14 KiB
Markdown
[futures.task]
|
||
|
||
# 32 Concurrency support library [[thread]](./#thread)
|
||
|
||
## 32.10 Futures [[futures]](futures#task)
|
||
|
||
### 32.10.10 Class template packaged_task [futures.task]
|
||
|
||
#### [32.10.10.1](#general) General [[futures.task.general]](futures.task.general)
|
||
|
||
[1](#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[.](#general-1.sentence-1)
|
||
|
||
[2](#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[.](#general-2.sentence-1)
|
||
|
||
Any futures that
|
||
share the shared state will then be able to access the stored result[.](#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](#members) Member functions [[futures.task.members]](futures.task.members)
|
||
|
||
[ð](#lib:packaged_task,constructor)
|
||
|
||
`packaged_task() noexcept;
|
||
`
|
||
|
||
[1](#members-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12606)
|
||
|
||
*Effects*: The object has no shared state and no stored task[.](#members-1.sentence-1)
|
||
|
||
[ð](#lib:packaged_task,constructor_)
|
||
|
||
`template<class F>
|
||
explicit packaged_task(F&& f);
|
||
`
|
||
|
||
[2](#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))[.](#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](#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...)>[.](#members-3.sentence-1)
|
||
|
||
[4](#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[.](#members-4.sentence-1)
|
||
|
||
[5](#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"))[.](#members-5.sentence-1)
|
||
|
||
[6](#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)[.](#members-6.sentence-1)
|
||
|
||
Constructs a new packaged_task object with
|
||
a stored task of type decay_t<F> and a shared state[.](#members-6.sentence-2)
|
||
|
||
Initializes the object's stored task with std::forward<F>(f)[.](#members-6.sentence-3)
|
||
|
||
Uses a2 to allocate storage for the shared state and stores a copy
|
||
of a2 in the shared state[.](#members-6.sentence-4)
|
||
|
||
[7](#members-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12656)
|
||
|
||
*Throws*: Any exceptions thrown by the initialization of the stored task[.](#members-7.sentence-1)
|
||
|
||
If storage for the shared state cannot be allocated, any exception thrown byA2::allocate[.](#members-7.sentence-2)
|
||
|
||
[ð](#lib:packaged_task,constructor___)
|
||
|
||
`template<class F> packaged_task(F) -> packaged_task<see below>;
|
||
`
|
||
|
||
[8](#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)](#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)](#members-8.2)
|
||
|
||
F::operator() is a static member function anddecltype(&F::operator()) is of the formR(*)(A...) noexceptopt[.](#members-8.sentence-1)
|
||
|
||
[9](#members-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12687)
|
||
|
||
*Remarks*: The deduced type is packaged_task<R(A...)>[.](#members-9.sentence-1)
|
||
|
||
[ð](#lib:packaged_task,constructor____)
|
||
|
||
`packaged_task(packaged_task&& rhs) noexcept;
|
||
`
|
||
|
||
[10](#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[.](#members-10.sentence-1)
|
||
|
||
Moves the stored task from rhs to *this[.](#members-10.sentence-2)
|
||
|
||
[11](#members-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12704)
|
||
|
||
*Postconditions*: rhs has no shared state[.](#members-11.sentence-1)
|
||
|
||
[ð](#lib:operator=,packaged_task)
|
||
|
||
`packaged_task& operator=(packaged_task&& rhs) noexcept;
|
||
`
|
||
|
||
[12](#members-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12715)
|
||
|
||
*Effects*:
|
||
|
||
- [(12.1)](#members-12.1)
|
||
|
||
Releases any shared state ([[futures.state]](futures.state "32.10.5 Shared state"));
|
||
|
||
- [(12.2)](#members-12.2)
|
||
|
||
calls packaged_task(std::move(rhs)).swap(*this)[.](#members-12.sentence-1)
|
||
|
||
[ð](#lib:packaged_task,destructor)
|
||
|
||
`~packaged_task();
|
||
`
|
||
|
||
[13](#members-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12731)
|
||
|
||
*Effects*: Abandons any shared state ([[futures.state]](futures.state "32.10.5 Shared state"))[.](#members-13.sentence-1)
|
||
|
||
[ð](#lib:swap,packaged_task)
|
||
|
||
`void swap(packaged_task& other) noexcept;
|
||
`
|
||
|
||
[14](#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[.](#members-14.sentence-1)
|
||
|
||
[15](#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[.](#members-15.sentence-1)
|
||
|
||
other has the same shared state
|
||
and stored task (if any)
|
||
as *this prior to the call to swap[.](#members-15.sentence-2)
|
||
|
||
[ð](#lib:valid,packaged_task)
|
||
|
||
`bool valid() const noexcept;
|
||
`
|
||
|
||
[16](#members-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12761)
|
||
|
||
*Returns*: true only if *this has a shared state[.](#members-16.sentence-1)
|
||
|
||
[ð](#lib:get_future,packaged_task)
|
||
|
||
`future<R> get_future();
|
||
`
|
||
|
||
[17](#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[.](#members-17.sentence-1)
|
||
|
||
[*Note [1](#members-note-1)*:
|
||
|
||
Such calls need not synchronize with each other[.](#members-17.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[18](#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[.](#members-18.sentence-1)
|
||
|
||
[19](#members-19)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12786)
|
||
|
||
*Throws*: A future_error object if an error occurs[.](#members-19.sentence-1)
|
||
|
||
[20](#members-20)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12790)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(20.1)](#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[.](#members-20.1.sentence-1)
|
||
|
||
- [(20.2)](#members-20.2)
|
||
|
||
no_state if *this has no shared state[.](#members-20.2.sentence-1)
|
||
|
||
[ð](#lib:operator(),packaged_task)
|
||
|
||
`void operator()(ArgTypes... args);
|
||
`
|
||
|
||
[21](#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...[.](#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[.](#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[.](#members-21.sentence-3)
|
||
|
||
[22](#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[.](#members-22.sentence-1)
|
||
|
||
[23](#members-23)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12822)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(23.1)](#members-23.1)
|
||
|
||
promise_already_satisfied if
|
||
the stored task has already been invoked[.](#members-23.1.sentence-1)
|
||
|
||
- [(23.2)](#members-23.2)
|
||
|
||
no_state if *this has no shared state[.](#members-23.2.sentence-1)
|
||
|
||
[ð](#lib:make_ready_at_thread_exit,packaged_task)
|
||
|
||
`void make_ready_at_thread_exit(ArgTypes... args);
|
||
`
|
||
|
||
[24](#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...[.](#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[.](#members-24.sentence-2)
|
||
|
||
In either
|
||
case, this is done without making that state ready ([[futures.state]](futures.state "32.10.5 Shared state")) immediately[.](#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[.](#members-24.sentence-4)
|
||
|
||
[25](#members-25)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12849)
|
||
|
||
*Throws*: future_error if an error condition occurs[.](#members-25.sentence-1)
|
||
|
||
[26](#members-26)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12853)
|
||
|
||
*Error conditions*:
|
||
|
||
- [(26.1)](#members-26.1)
|
||
|
||
promise_already_satisfied if the
|
||
stored task has already been invoked[.](#members-26.1.sentence-1)
|
||
|
||
- [(26.2)](#members-26.2)
|
||
|
||
no_state if *this has no shared state[.](#members-26.2.sentence-1)
|
||
|
||
[ð](#lib:reset,packaged_task)
|
||
|
||
`void reset();
|
||
`
|
||
|
||
[27](#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[.](#members-27.sentence-1)
|
||
|
||
[*Note [2](#members-note-2)*:
|
||
|
||
This constructs a new shared state for *this[.](#members-27.sentence-2)
|
||
|
||
The
|
||
old state is abandoned ([[futures.state]](futures.state "32.10.5 Shared state"))[.](#members-27.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[28](#members-28)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12885)
|
||
|
||
*Throws*:
|
||
|
||
- [(28.1)](#members-28.1)
|
||
|
||
Any exception thrown by the packaged_task constructor[.](#members-28.1.sentence-1)
|
||
|
||
- [(28.2)](#members-28.2)
|
||
|
||
future_error with an error condition of no_state if *this has no shared state[.](#members-28.2.sentence-1)
|
||
|
||
#### [32.10.10.3](#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](#nonmembers-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12903)
|
||
|
||
*Effects*: As if by x.swap(y)[.](#nonmembers-1.sentence-1)
|