This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

393
cppdraft/futures/task.md Normal file
View File

@@ -0,0 +1,393 @@
[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.1General"))[.](#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.3Context 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.5Shared 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.5Shared 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.2Multi-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.4Requirements")),
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.4Requirements")),
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.5Shared 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.5Shared 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)