Init
This commit is contained in:
190
cppdraft/futures/async.md
Normal file
190
cppdraft/futures/async.md
Normal file
@@ -0,0 +1,190 @@
|
||||
[futures.async]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#async)
|
||||
|
||||
### 32.10.9 Function template async [futures.async]
|
||||
|
||||
[1](#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[.](#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](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12389)
|
||||
|
||||
*Mandates*: The following are all true:
|
||||
|
||||
- [(2.1)](#2.1)
|
||||
|
||||
is_constructible_v<decay_t<F>, F>,
|
||||
|
||||
- [(2.2)](#2.2)
|
||||
|
||||
(is_constructible_v<decay_t<Args>, Args> && ...), and
|
||||
|
||||
- [(2.3)](#2.3)
|
||||
|
||||
is_invocable_v<decay_t<F>, decay_t<Args>...>[.](#2.sentence-1)
|
||||
|
||||
[3](#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[.](#3.sentence-1)
|
||||
|
||||
The second function creates a shared state that is associated with
|
||||
the returned future object[.](#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)](#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[.](#3.1.sentence-1)
|
||||
Any return value
|
||||
is stored as the result in the
|
||||
shared state[.](#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[.](#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[.](#3.1.sentence-4)
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
If launch::deferred is set in policy,
|
||||
stores auto(std::forward<F>(f)) andauto(std::forward<Args>(args))... in the shared state[.](#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]")[.](#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))...[.](#3.2.sentence-3)
|
||||
Any return value is stored
|
||||
as the result in the shared state[.](#3.2.sentence-4)
|
||||
Any exception propagated
|
||||
from the execution
|
||||
of the deferred function
|
||||
is stored as the exceptional result
|
||||
in the shared state[.](#3.2.sentence-5)
|
||||
The shared state is not
|
||||
made ready until the function has completed[.](#3.2.sentence-6)
|
||||
The first call to a
|
||||
non-timed waiting function ([[futures.state]](futures.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[.](#3.2.sentence-7)
|
||||
Once evaluation of invoke(std::move(g), std::move(xyz)) begins, the function is no longer
|
||||
considered deferred[.](#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[.](#3.2.sentence-9)
|
||||
|
||||
- [(3.3)](#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[.](#3.3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12464)
|
||||
|
||||
*Synchronization*: The invocation of async synchronizes with the invocation of f[.](#4.sentence-1)
|
||||
|
||||
The completion of the function f is sequenced before
|
||||
the shared state is made ready[.](#4.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
These apply regardless of the provided policy argument, and
|
||||
even if the corresponding future object is moved to another thread[.](#4.sentence-3)
|
||||
|
||||
However, it is possible for f not to be called at all,
|
||||
in which case its completion never happens[.](#4.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
If the implementation chooses the launch::async policy,
|
||||
|
||||
- [(4.1)](#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)](#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[.](#4.sentence-5)
|
||||
|
||||
[5](#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[.](#5.sentence-1)
|
||||
|
||||
[*Note [2](#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[.](#5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#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[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12511)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(7.1)](#7.1)
|
||||
|
||||
resource_unavailable_try_again â ifpolicy == launch::async and the system is unable to start a new thread[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12519)
|
||||
|
||||
[*Example [1](#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](#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[.](#8.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
â *end example*]
|
||||
49
cppdraft/futures/errors.md
Normal file
49
cppdraft/futures/errors.md
Normal file
@@ -0,0 +1,49 @@
|
||||
[futures.errors]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#errors)
|
||||
|
||||
### 32.10.3 Error handling [futures.errors]
|
||||
|
||||
[ð](#lib:future_category)
|
||||
|
||||
`const error_category& future_category() noexcept;
|
||||
`
|
||||
|
||||
[1](#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[.](#1.sentence-1)
|
||||
|
||||
[2](#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[.](#2.sentence-1)
|
||||
|
||||
The object's name virtual function returns a pointer to the string "future"[.](#2.sentence-2)
|
||||
|
||||
[ð](#lib:make_error_code,future_errc)
|
||||
|
||||
`error_code make_error_code(future_errc e) noexcept;
|
||||
`
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11242)
|
||||
|
||||
*Returns*: error_code(static_cast<int>(e), future_category())[.](#3.sentence-1)
|
||||
|
||||
[ð](#lib:make_error_condition,future_errc)
|
||||
|
||||
`error_condition make_error_condition(future_errc e) noexcept;
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11253)
|
||||
|
||||
*Returns*: error_condition(static_cast<int>(e), future_category())[.](#4.sentence-1)
|
||||
44
cppdraft/futures/future/error.md
Normal file
44
cppdraft/futures/future/error.md
Normal file
@@ -0,0 +1,44 @@
|
||||
[futures.future.error]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#future.error)
|
||||
|
||||
### 32.10.4 Class 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](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11282)
|
||||
|
||||
*Effects*: Initializes ec_ with make_error_code(e)[.](#1.sentence-1)
|
||||
|
||||
[ð](#lib:code,future_error)
|
||||
|
||||
`const error_code& code() const noexcept;
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11293)
|
||||
|
||||
*Returns*: ec_[.](#2.sentence-1)
|
||||
|
||||
[ð](#lib:what,future_error)
|
||||
|
||||
`const char* what() const noexcept;
|
||||
`
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11304)
|
||||
|
||||
*Returns*: An ntbs incorporating code().message()[.](#3.sentence-1)
|
||||
21
cppdraft/futures/overview.md
Normal file
21
cppdraft/futures/overview.md
Normal file
@@ -0,0 +1,21 @@
|
||||
[futures.overview]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#overview)
|
||||
|
||||
### 32.10.1 Overview [futures.overview]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11126)
|
||||
|
||||
[[futures]](futures "32.10 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[.](#1.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
These components are not restricted to multi-threaded programs but can be useful in
|
||||
single-threaded programs as well[.](#1.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
366
cppdraft/futures/promise.md
Normal file
366
cppdraft/futures/promise.md
Normal file
@@ -0,0 +1,366 @@
|
||||
[futures.promise]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#promise)
|
||||
|
||||
### 32.10.6 Class template 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](#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[.](#1.sentence-1)
|
||||
|
||||
[2](#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>[.](#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[.](#2.sentence-2)
|
||||
|
||||
[3](#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[.](#3.sentence-1)
|
||||
|
||||
[ð](#lib:promise,constructor)
|
||||
|
||||
`promise();
|
||||
template<class Allocator>
|
||||
promise(allocator_arg_t, const Allocator& a);
|
||||
`
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11479)
|
||||
|
||||
*Effects*: Creates a shared state[.](#4.sentence-1)
|
||||
|
||||
The second
|
||||
constructor uses the allocator a to allocate memory for the shared
|
||||
state[.](#4.sentence-2)
|
||||
|
||||
[ð](#lib:promise,constructor_)
|
||||
|
||||
`promise(promise&& rhs) noexcept;
|
||||
`
|
||||
|
||||
[5](#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[.](#5.sentence-1)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11497)
|
||||
|
||||
*Postconditions*: rhs has no shared state[.](#6.sentence-1)
|
||||
|
||||
[ð](#lib:promise,destructor)
|
||||
|
||||
`~promise();
|
||||
`
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11508)
|
||||
|
||||
*Effects*: Abandons any shared state ([[futures.state]](futures.state "32.10.5 Shared state"))[.](#7.sentence-1)
|
||||
|
||||
[ð](#lib:operator=,promise)
|
||||
|
||||
`promise& operator=(promise&& rhs) noexcept;
|
||||
`
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11519)
|
||||
|
||||
*Effects*: Abandons any shared state ([[futures.state]](futures.state "32.10.5 Shared state")) and then as ifpromise(std::move(rhs)).swap(*this)[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11524)
|
||||
|
||||
*Returns*: *this[.](#9.sentence-1)
|
||||
|
||||
[ð](#lib:swap,promise)
|
||||
|
||||
`void swap(promise& other) noexcept;
|
||||
`
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11535)
|
||||
|
||||
*Effects*: Exchanges the shared state of *this and other[.](#10.sentence-1)
|
||||
|
||||
[11](#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[.](#11.sentence-1)
|
||||
|
||||
other has the shared state (if any) that*this had prior to the call to swap[.](#11.sentence-2)
|
||||
|
||||
[ð](#lib:get_future,promise)
|
||||
|
||||
`future<R> get_future();
|
||||
`
|
||||
|
||||
[12](#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[.](#12.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Such calls need not synchronize with each other[.](#12.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11564)
|
||||
|
||||
*Returns*: A future<R> object with the same shared state as*this[.](#13.sentence-1)
|
||||
|
||||
[14](#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[.](#14.sentence-1)
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11575)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(15.1)](#15.1)
|
||||
|
||||
future_already_retrieved if get_future has already been called on
|
||||
a promise with the same shared state as *this[.](#15.1.sentence-1)
|
||||
|
||||
- [(15.2)](#15.2)
|
||||
|
||||
no_state if *this has no shared state[.](#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](#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]](futures.state "32.10.5 Shared state"))[.](#16.sentence-1)
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11599)
|
||||
|
||||
*Throws*:
|
||||
|
||||
- [(17.1)](#17.1)
|
||||
|
||||
future_error if its shared state
|
||||
already has a stored value or exception, or
|
||||
|
||||
- [(17.2)](#17.2)
|
||||
|
||||
for the first version, any exception thrown by the constructor selected to copy an object of R, or
|
||||
|
||||
- [(17.3)](#17.3)
|
||||
|
||||
for the second version, any exception thrown by the constructor selected to move an object of R[.](#17.sentence-1)
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11608)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(18.1)](#18.1)
|
||||
|
||||
promise_already_satisfied if its shared state
|
||||
already has a stored value or exception[.](#18.1.sentence-1)
|
||||
|
||||
- [(18.2)](#18.2)
|
||||
|
||||
no_state if *this has no shared state[.](#18.2.sentence-1)
|
||||
|
||||
[ð](#lib:set_exception,promise)
|
||||
|
||||
`void set_exception(exception_ptr p);
|
||||
`
|
||||
|
||||
[19](#19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11623)
|
||||
|
||||
*Preconditions*: p is not null[.](#19.sentence-1)
|
||||
|
||||
[20](#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]](futures.state "32.10.5 Shared state"))[.](#20.sentence-1)
|
||||
|
||||
[21](#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[.](#21.sentence-1)
|
||||
|
||||
[22](#22)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11637)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(22.1)](#22.1)
|
||||
|
||||
promise_already_satisfied if its shared state
|
||||
already has a stored value or exception[.](#22.1.sentence-1)
|
||||
|
||||
- [(22.2)](#22.2)
|
||||
|
||||
no_state if *this has no shared state[.](#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](#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[.](#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[.](#23.sentence-2)
|
||||
|
||||
[24](#24)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11662)
|
||||
|
||||
*Throws*:
|
||||
|
||||
- [(24.1)](#24.1)
|
||||
|
||||
future_error if its shared state
|
||||
already has a stored value or exception, or
|
||||
|
||||
- [(24.2)](#24.2)
|
||||
|
||||
for the first version, any exception thrown by the constructor selected to copy an object of R, or
|
||||
|
||||
- [(24.3)](#24.3)
|
||||
|
||||
for the second version, any exception thrown by the constructor selected to move an object of R[.](#24.sentence-1)
|
||||
|
||||
[25](#25)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11671)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(25.1)](#25.1)
|
||||
|
||||
promise_already_satisfied if its shared state
|
||||
already has a stored value or exception[.](#25.1.sentence-1)
|
||||
|
||||
- [(25.2)](#25.2)
|
||||
|
||||
no_state if *this has no shared state[.](#25.2.sentence-1)
|
||||
|
||||
[ð](#lib:set_exception_at_thread_exit,promise)
|
||||
|
||||
`void set_exception_at_thread_exit(exception_ptr p);
|
||||
`
|
||||
|
||||
[26](#26)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11686)
|
||||
|
||||
*Preconditions*: p is not null[.](#26.sentence-1)
|
||||
|
||||
[27](#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[.](#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[.](#27.sentence-2)
|
||||
|
||||
[28](#28)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11697)
|
||||
|
||||
*Throws*: future_error if an error condition occurs[.](#28.sentence-1)
|
||||
|
||||
[29](#29)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11701)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(29.1)](#29.1)
|
||||
|
||||
promise_already_satisfied if its shared state
|
||||
already has a stored value or exception[.](#29.1.sentence-1)
|
||||
|
||||
- [(29.2)](#29.2)
|
||||
|
||||
no_state if *this has no shared state[.](#29.2.sentence-1)
|
||||
|
||||
[ð](#lib:swap,promise_)
|
||||
|
||||
`template<class R>
|
||||
void swap(promise<R>& x, promise<R>& y) noexcept;
|
||||
`
|
||||
|
||||
[30](#30)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11717)
|
||||
|
||||
*Effects*: As if by x.swap(y)[.](#30.sentence-1)
|
||||
404
cppdraft/futures/shared/future.md
Normal file
404
cppdraft/futures/shared/future.md
Normal file
@@ -0,0 +1,404 @@
|
||||
[futures.shared.future]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#shared.future)
|
||||
|
||||
### 32.10.8 Class template shared_future [futures.shared.future]
|
||||
|
||||
[1](#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[.](#1.sentence-1)
|
||||
|
||||
A default-constructed shared_future object has no shared state[.](#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](futures.state#def:asynchronous_provider "32.10.5 Shared state [futures.state]") of the shared state[.](#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[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12045)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Member functions of shared_future do not synchronize with themselves,
|
||||
but they synchronize with the shared state[.](#2.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#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[.](#3.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
It is valid to copy or move from a shared_future object for which valid() is false[.](#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[.](#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](#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[.](#4.sentence-1)
|
||||
|
||||
[5](#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>[.](#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[.](#5.sentence-2)
|
||||
|
||||
[ð](#lib:shared_future,constructor)
|
||||
|
||||
`shared_future() noexcept;
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12109)
|
||||
|
||||
*Effects*: The object does not refer to a shared state[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12113)
|
||||
|
||||
*Postconditions*: valid() == false[.](#7.sentence-1)
|
||||
|
||||
[ð](#lib:shared_future,constructor_)
|
||||
|
||||
`shared_future(const shared_future& rhs) noexcept;
|
||||
`
|
||||
|
||||
[8](#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)[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12129)
|
||||
|
||||
*Postconditions*: valid() returns the same value as rhs.valid()[.](#9.sentence-1)
|
||||
|
||||
[ð](#lib:shared_future,constructor__)
|
||||
|
||||
`shared_future(future<R>&& rhs) noexcept;
|
||||
shared_future(shared_future&& rhs) noexcept;
|
||||
`
|
||||
|
||||
[10](#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)[.](#10.sentence-1)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12146)
|
||||
|
||||
*Postconditions*:
|
||||
|
||||
- [(11.1)](#11.1)
|
||||
|
||||
valid() returns the same value as rhs.valid() returned prior to
|
||||
the constructor invocation[.](#11.1.sentence-1)
|
||||
|
||||
- [(11.2)](#11.2)
|
||||
|
||||
rhs.valid() == false[.](#11.2.sentence-1)
|
||||
|
||||
[ð](#lib:shared_future,destructor)
|
||||
|
||||
`~shared_future();
|
||||
`
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12161)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(12.1)](#12.1)
|
||||
|
||||
Releases any shared state ([[futures.state]](futures.state "32.10.5 Shared state"));
|
||||
|
||||
- [(12.2)](#12.2)
|
||||
|
||||
destroys *this[.](#12.sentence-1)
|
||||
|
||||
[ð](#lib:operator=,shared_future)
|
||||
|
||||
`shared_future& operator=(shared_future&& rhs) noexcept;
|
||||
`
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12177)
|
||||
|
||||
*Effects*: If addressof(rhs) == this is true, there are no effects[.](#13.sentence-1)
|
||||
|
||||
Otherwise:
|
||||
|
||||
- [(13.1)](#13.1)
|
||||
|
||||
Releases any shared state ([[futures.state]](futures.state "32.10.5 Shared state"));
|
||||
|
||||
- [(13.2)](#13.2)
|
||||
|
||||
move assigns the contents of rhs to *this[.](#13.sentence-2)
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12188)
|
||||
|
||||
*Postconditions*:
|
||||
|
||||
- [(14.1)](#14.1)
|
||||
|
||||
valid() returns the same value as rhs.valid() returned prior to
|
||||
the assignment[.](#14.1.sentence-1)
|
||||
|
||||
- [(14.2)](#14.2)
|
||||
|
||||
If addressof(rhs) == this is false,rhs.valid() == false[.](#14.2.sentence-1)
|
||||
|
||||
[ð](#lib:operator=,shared_future_)
|
||||
|
||||
`shared_future& operator=(const shared_future& rhs) noexcept;
|
||||
`
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12207)
|
||||
|
||||
*Effects*: If addressof(rhs) == this is true, there are no effects[.](#15.sentence-1)
|
||||
|
||||
Otherwise:
|
||||
|
||||
- [(15.1)](#15.1)
|
||||
|
||||
Releases any shared state ([[futures.state]](futures.state "32.10.5 Shared state"));
|
||||
|
||||
- [(15.2)](#15.2)
|
||||
|
||||
assigns the contents of rhs to *this[.](#15.sentence-2)
|
||||
[*Note [3](#note-3)*:
|
||||
As a result,*this refers to the same shared state as rhs (if any)[.](#15.2.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12223)
|
||||
|
||||
*Postconditions*: valid() == rhs.valid()[.](#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](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12236)
|
||||
|
||||
[*Note [4](#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[.](#17.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12242)
|
||||
|
||||
[*Note [5](#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"))[.](#18.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[19](#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[.](#19.sentence-1)
|
||||
|
||||
[20](#20)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12254)
|
||||
|
||||
*Returns*:
|
||||
|
||||
- [(20.1)](#20.1)
|
||||
|
||||
shared_future::get() returns a const reference to the value stored in the object's
|
||||
shared state[.](#20.1.sentence-1)
|
||||
[*Note [6](#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[.](#20.1.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
- [(20.2)](#20.2)
|
||||
|
||||
shared_future<R&>::get() returns the reference stored as value in the object's
|
||||
shared state[.](#20.2.sentence-1)
|
||||
|
||||
- [(20.3)](#20.3)
|
||||
|
||||
shared_future<void>::get() returns nothing[.](#20.3.sentence-1)
|
||||
|
||||
[21](#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[.](#21.sentence-1)
|
||||
|
||||
[ð](#lib:valid,shared_future)
|
||||
|
||||
`bool valid() const noexcept;
|
||||
`
|
||||
|
||||
[22](#22)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12286)
|
||||
|
||||
*Returns*: true only if *this refers to a shared state[.](#22.sentence-1)
|
||||
|
||||
[ð](#lib:wait,shared_future)
|
||||
|
||||
`void wait() const;
|
||||
`
|
||||
|
||||
[23](#23)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12297)
|
||||
|
||||
*Effects*: Blocks until the shared state is ready[.](#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](#24)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12310)
|
||||
|
||||
*Effects*: None if the shared state contains a deferred function ([[futures.async]](futures.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[.](#24.sentence-1)
|
||||
|
||||
[25](#25)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12319)
|
||||
|
||||
*Returns*:
|
||||
|
||||
- [(25.1)](#25.1)
|
||||
|
||||
future_status::deferred if the shared state contains a deferred
|
||||
function[.](#25.1.sentence-1)
|
||||
|
||||
- [(25.2)](#25.2)
|
||||
|
||||
future_status::ready if the shared state is ready[.](#25.2.sentence-1)
|
||||
|
||||
- [(25.3)](#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[.](#25.3.sentence-1)
|
||||
|
||||
[26](#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"))[.](#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](#27)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12344)
|
||||
|
||||
*Effects*: None if the shared state contains a deferred function ([[futures.async]](futures.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[.](#27.sentence-1)
|
||||
|
||||
[28](#28)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12353)
|
||||
|
||||
*Returns*:
|
||||
|
||||
- [(28.1)](#28.1)
|
||||
|
||||
future_status::deferred if the shared state contains a deferred
|
||||
function[.](#28.1.sentence-1)
|
||||
|
||||
- [(28.2)](#28.2)
|
||||
|
||||
future_status::ready if the shared state is ready[.](#28.2.sentence-1)
|
||||
|
||||
- [(28.3)](#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[.](#28.3.sentence-1)
|
||||
|
||||
[29](#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"))[.](#29.sentence-1)
|
||||
177
cppdraft/futures/state.md
Normal file
177
cppdraft/futures/state.md
Normal file
@@ -0,0 +1,177 @@
|
||||
[futures.state]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#state)
|
||||
|
||||
### 32.10.5 Shared state [futures.state]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11311)
|
||||
|
||||
Many of the classes introduced in subclause [[futures]](futures "32.10 Futures") use some state to communicate results[.](#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[.](#1.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Futures, promises, and tasks defined in this Clause reference such shared state[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11320)
|
||||
|
||||
[*Note [2](#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[.](#2.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#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[.](#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[.](#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)[.](#3.sentence-3)
|
||||
|
||||
[4](#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[.](#4.sentence-1)
|
||||
|
||||
The result of a shared state is set by
|
||||
respective functions on the asynchronous provider[.](#4.sentence-2)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
Promises and tasks are examples of asynchronous providers[.](#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[.](#4.sentence-4)
|
||||
|
||||
[5](#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)](#5.1)
|
||||
|
||||
if the return object or provider holds the last reference to its shared state,
|
||||
the shared state is destroyed; and
|
||||
|
||||
- [(5.2)](#5.2)
|
||||
|
||||
the return object or provider gives up its reference to its shared state; and
|
||||
|
||||
- [(5.3)](#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[.](#5.sentence-1)
|
||||
|
||||
[6](#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)](#6.1)
|
||||
|
||||
first, the provider marks its shared state as ready; and
|
||||
|
||||
- [(6.2)](#6.2)
|
||||
|
||||
second, the provider unblocks any execution agents waiting for its shared
|
||||
state to become ready[.](#6.sentence-1)
|
||||
|
||||
[7](#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)](#7.1)
|
||||
|
||||
first, if that state is not ready, the provider
|
||||
* [(7.1.1)](#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)](#7.1.2)
|
||||
|
||||
makes its shared state ready;
|
||||
|
||||
- [(7.2)](#7.2)
|
||||
|
||||
second, the provider releases its shared state[.](#7.sentence-1)
|
||||
|
||||
[8](#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[.](#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[.](#8.sentence-2)
|
||||
|
||||
[9](#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[.](#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[.](#9.sentence-2)
|
||||
|
||||
[10](#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[.](#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[.](#10.sentence-2)
|
||||
|
||||
[11](#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]")[.](#11.sentence-1)
|
||||
|
||||
[*Note [3](#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"))[.](#11.sentence-2)
|
||||
|
||||
For example, concurrent accesses through
|
||||
references returned by shared_future::get() ([[futures.shared.future]](futures.shared.future "32.10.8 Class template shared_future"))
|
||||
must either use read-only operations or provide additional synchronization[.](#11.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
393
cppdraft/futures/task.md
Normal file
393
cppdraft/futures/task.md
Normal 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.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)
|
||||
33
cppdraft/futures/task/general.md
Normal file
33
cppdraft/futures/task/general.md
Normal file
@@ -0,0 +1,33 @@
|
||||
[futures.task.general]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#task.general)
|
||||
|
||||
### 32.10.10 Class template packaged_task [[futures.task]](futures.task#general)
|
||||
|
||||
#### 32.10.10.1 General [futures.task.general]
|
||||
|
||||
[1](#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[.](#1.sentence-1)
|
||||
|
||||
[2](#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[.](#2.sentence-1)
|
||||
|
||||
Any futures that
|
||||
share the shared state will then be able to access the stored result[.](#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*>;}
|
||||
353
cppdraft/futures/task/members.md
Normal file
353
cppdraft/futures/task/members.md
Normal file
@@ -0,0 +1,353 @@
|
||||
[futures.task.members]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#task.members)
|
||||
|
||||
### 32.10.10 Class template packaged_task [[futures.task]](futures.task#members)
|
||||
|
||||
#### 32.10.10.2 Member functions [futures.task.members]
|
||||
|
||||
[ð](#lib:packaged_task,constructor)
|
||||
|
||||
`packaged_task() noexcept;
|
||||
`
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12606)
|
||||
|
||||
*Effects*: The object has no shared state and no stored task[.](#1.sentence-1)
|
||||
|
||||
[ð](#lib:packaged_task,constructor_)
|
||||
|
||||
`template<class F>
|
||||
explicit packaged_task(F&& f);
|
||||
`
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12618)
|
||||
|
||||
*Effects*: Equivalent topackaged_task(allocator_arg, allocator<int>(), std::forward<F>(f))[.](#2.sentence-1)
|
||||
|
||||
[ð](#lib:packaged_task,constructor__)
|
||||
|
||||
`template<class F, class Allocator>
|
||||
explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f);
|
||||
`
|
||||
|
||||
[3](#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...)>[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12636)
|
||||
|
||||
*Mandates*: is_invocable_r_v<R, decay_t<F>&, ArgTypes...> is true[.](#4.sentence-1)
|
||||
|
||||
[5](#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"))[.](#5.sentence-1)
|
||||
|
||||
[6](#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)[.](#6.sentence-1)
|
||||
|
||||
Constructs a new packaged_task object with
|
||||
a stored task of type decay_t<F> and a shared state[.](#6.sentence-2)
|
||||
|
||||
Initializes the object's stored task with std::forward<F>(f)[.](#6.sentence-3)
|
||||
|
||||
Uses a2 to allocate storage for the shared state and stores a copy
|
||||
of a2 in the shared state[.](#6.sentence-4)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12656)
|
||||
|
||||
*Throws*: Any exceptions thrown by the initialization of the stored task[.](#7.sentence-1)
|
||||
|
||||
If storage for the shared state cannot be allocated, any exception thrown byA2::allocate[.](#7.sentence-2)
|
||||
|
||||
[ð](#lib:packaged_task,constructor___)
|
||||
|
||||
`template<class F> packaged_task(F) -> packaged_task<see below>;
|
||||
`
|
||||
|
||||
[8](#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)](#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)](#8.2)
|
||||
|
||||
F::operator() is a static member function anddecltype(&F::operator()) is of the formR(*)(A...) noexceptopt[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12687)
|
||||
|
||||
*Remarks*: The deduced type is packaged_task<R(A...)>[.](#9.sentence-1)
|
||||
|
||||
[ð](#lib:packaged_task,constructor____)
|
||||
|
||||
`packaged_task(packaged_task&& rhs) noexcept;
|
||||
`
|
||||
|
||||
[10](#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[.](#10.sentence-1)
|
||||
|
||||
Moves the stored task from rhs to *this[.](#10.sentence-2)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12704)
|
||||
|
||||
*Postconditions*: rhs has no shared state[.](#11.sentence-1)
|
||||
|
||||
[ð](#lib:operator=,packaged_task)
|
||||
|
||||
`packaged_task& operator=(packaged_task&& rhs) noexcept;
|
||||
`
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12715)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(12.1)](#12.1)
|
||||
|
||||
Releases any shared state ([[futures.state]](futures.state "32.10.5 Shared state"));
|
||||
|
||||
- [(12.2)](#12.2)
|
||||
|
||||
calls packaged_task(std::move(rhs)).swap(*this)[.](#12.sentence-1)
|
||||
|
||||
[ð](#lib:packaged_task,destructor)
|
||||
|
||||
`~packaged_task();
|
||||
`
|
||||
|
||||
[13](#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"))[.](#13.sentence-1)
|
||||
|
||||
[ð](#lib:swap,packaged_task)
|
||||
|
||||
`void swap(packaged_task& other) noexcept;
|
||||
`
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12742)
|
||||
|
||||
*Effects*: Exchanges the shared states and stored tasks of *this and other[.](#14.sentence-1)
|
||||
|
||||
[15](#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[.](#15.sentence-1)
|
||||
|
||||
other has the same shared state
|
||||
and stored task (if any)
|
||||
as *this prior to the call to swap[.](#15.sentence-2)
|
||||
|
||||
[ð](#lib:valid,packaged_task)
|
||||
|
||||
`bool valid() const noexcept;
|
||||
`
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12761)
|
||||
|
||||
*Returns*: true only if *this has a shared state[.](#16.sentence-1)
|
||||
|
||||
[ð](#lib:get_future,packaged_task)
|
||||
|
||||
`future<R> get_future();
|
||||
`
|
||||
|
||||
[17](#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[.](#17.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Such calls need not synchronize with each other[.](#17.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12782)
|
||||
|
||||
*Returns*: A future object that shares the same shared state as *this[.](#18.sentence-1)
|
||||
|
||||
[19](#19)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12786)
|
||||
|
||||
*Throws*: A future_error object if an error occurs[.](#19.sentence-1)
|
||||
|
||||
[20](#20)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12790)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(20.1)](#20.1)
|
||||
|
||||
future_already_retrieved if get_future has already been called on
|
||||
a packaged_task object with the same shared state as *this[.](#20.1.sentence-1)
|
||||
|
||||
- [(20.2)](#20.2)
|
||||
|
||||
no_state if *this has no shared state[.](#20.2.sentence-1)
|
||||
|
||||
[ð](#lib:operator(),packaged_task)
|
||||
|
||||
`void operator()(ArgTypes... args);
|
||||
`
|
||||
|
||||
[21](#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...[.](#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[.](#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[.](#21.sentence-3)
|
||||
|
||||
[22](#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[.](#22.sentence-1)
|
||||
|
||||
[23](#23)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12822)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(23.1)](#23.1)
|
||||
|
||||
promise_already_satisfied if
|
||||
the stored task has already been invoked[.](#23.1.sentence-1)
|
||||
|
||||
- [(23.2)](#23.2)
|
||||
|
||||
no_state if *this has no shared state[.](#23.2.sentence-1)
|
||||
|
||||
[ð](#lib:make_ready_at_thread_exit,packaged_task)
|
||||
|
||||
`void make_ready_at_thread_exit(ArgTypes... args);
|
||||
`
|
||||
|
||||
[24](#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...[.](#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[.](#24.sentence-2)
|
||||
|
||||
In either
|
||||
case, this is done without making that state ready ([[futures.state]](futures.state "32.10.5 Shared state")) immediately[.](#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[.](#24.sentence-4)
|
||||
|
||||
[25](#25)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12849)
|
||||
|
||||
*Throws*: future_error if an error condition occurs[.](#25.sentence-1)
|
||||
|
||||
[26](#26)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12853)
|
||||
|
||||
*Error conditions*:
|
||||
|
||||
- [(26.1)](#26.1)
|
||||
|
||||
promise_already_satisfied if the
|
||||
stored task has already been invoked[.](#26.1.sentence-1)
|
||||
|
||||
- [(26.2)](#26.2)
|
||||
|
||||
no_state if *this has no shared state[.](#26.2.sentence-1)
|
||||
|
||||
[ð](#lib:reset,packaged_task)
|
||||
|
||||
`void reset();
|
||||
`
|
||||
|
||||
[27](#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[.](#27.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
This constructs a new shared state for *this[.](#27.sentence-2)
|
||||
|
||||
The
|
||||
old state is abandoned ([[futures.state]](futures.state "32.10.5 Shared state"))[.](#27.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[28](#28)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12885)
|
||||
|
||||
*Throws*:
|
||||
|
||||
- [(28.1)](#28.1)
|
||||
|
||||
Any exception thrown by the packaged_task constructor[.](#28.1.sentence-1)
|
||||
|
||||
- [(28.2)](#28.2)
|
||||
|
||||
future_error with an error condition of no_state if *this has no shared state[.](#28.2.sentence-1)
|
||||
21
cppdraft/futures/task/nonmembers.md
Normal file
21
cppdraft/futures/task/nonmembers.md
Normal file
@@ -0,0 +1,21 @@
|
||||
[futures.task.nonmembers]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#task.nonmembers)
|
||||
|
||||
### 32.10.10 Class template packaged_task [[futures.task]](futures.task#nonmembers)
|
||||
|
||||
#### 32.10.10.3 Globals [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](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12903)
|
||||
|
||||
*Effects*: As if by x.swap(y)[.](#1.sentence-1)
|
||||
366
cppdraft/futures/unique/future.md
Normal file
366
cppdraft/futures/unique/future.md
Normal file
@@ -0,0 +1,366 @@
|
||||
[futures.unique.future]
|
||||
|
||||
# 32 Concurrency support library [[thread]](./#thread)
|
||||
|
||||
## 32.10 Futures [[futures]](futures#unique.future)
|
||||
|
||||
### 32.10.7 Class template future [futures.unique.future]
|
||||
|
||||
[1](#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[.](#1.sentence-1)
|
||||
|
||||
A default-constructed future object has no
|
||||
shared state[.](#1.sentence-2)
|
||||
|
||||
A future object with shared state can be created by
|
||||
functions on [asynchronous providers](futures.state#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[.](#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[.](#1.sentence-4)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11739)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Member functions of future do not synchronize with themselves or with
|
||||
member functions of shared_future[.](#2.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#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[.](#3.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
It is valid to move from a future object for which valid() == false[.](#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[.](#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](#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[.](#4.sentence-1)
|
||||
|
||||
[5](#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>[.](#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[.](#5.sentence-2)
|
||||
|
||||
[ð](#lib:future,constructor)
|
||||
|
||||
`future() noexcept;
|
||||
`
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11802)
|
||||
|
||||
*Effects*: The object does not refer to a shared state[.](#6.sentence-1)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11806)
|
||||
|
||||
*Postconditions*: valid() == false[.](#7.sentence-1)
|
||||
|
||||
[ð](#lib:future,constructor_)
|
||||
|
||||
`future(future&& rhs) noexcept;
|
||||
`
|
||||
|
||||
[8](#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)[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11823)
|
||||
|
||||
*Postconditions*:
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
valid() returns the same value as rhs.valid() prior to the
|
||||
constructor invocation[.](#9.1.sentence-1)
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
rhs.valid() == false[.](#9.2.sentence-1)
|
||||
|
||||
[ð](#lib:future,constructor__)
|
||||
|
||||
`~future();
|
||||
`
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11838)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(10.1)](#10.1)
|
||||
|
||||
Releases any shared state ([[futures.state]](futures.state "32.10.5 Shared state"));
|
||||
|
||||
- [(10.2)](#10.2)
|
||||
|
||||
destroys *this[.](#10.sentence-1)
|
||||
|
||||
[ð](#lib:operator=,future)
|
||||
|
||||
`future& operator=(future&& rhs) noexcept;
|
||||
`
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11854)
|
||||
|
||||
*Effects*: If addressof(rhs) == this is true, there are no effects[.](#11.sentence-1)
|
||||
|
||||
Otherwise:
|
||||
|
||||
- [(11.1)](#11.1)
|
||||
|
||||
Releases any shared state ([[futures.state]](futures.state "32.10.5 Shared state"))[.](#11.1.sentence-1)
|
||||
|
||||
- [(11.2)](#11.2)
|
||||
|
||||
move assigns the contents of rhs to *this[.](#11.2.sentence-1)
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11865)
|
||||
|
||||
*Postconditions*:
|
||||
|
||||
- [(12.1)](#12.1)
|
||||
|
||||
valid() returns the same value as rhs.valid() prior to the
|
||||
assignment[.](#12.1.sentence-1)
|
||||
|
||||
- [(12.2)](#12.2)
|
||||
|
||||
If addressof(rhs) == this is false,rhs.valid() == false[.](#12.2.sentence-1)
|
||||
|
||||
[ð](#lib:share,future)
|
||||
|
||||
`shared_future<R> share() noexcept;
|
||||
`
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11884)
|
||||
|
||||
*Postconditions*: valid() == false[.](#13.sentence-1)
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11888)
|
||||
|
||||
*Returns*: shared_future<R>(std::move(*this))[.](#14.sentence-1)
|
||||
|
||||
[ð](#lib:get,future)
|
||||
|
||||
`R future::get();
|
||||
R& future<R&>::get();
|
||||
void future<void>::get();
|
||||
`
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11901)
|
||||
|
||||
[*Note [3](#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[.](#15.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11907)
|
||||
|
||||
*Effects*:
|
||||
|
||||
- [(16.1)](#16.1)
|
||||
|
||||
wait()s until the shared state is ready, then retrieves the
|
||||
value stored in the shared state;
|
||||
|
||||
- [(16.2)](#16.2)
|
||||
|
||||
releases any shared state ([[futures.state]](futures.state "32.10.5 Shared state"))[.](#16.sentence-1)
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11915)
|
||||
|
||||
*Postconditions*: valid() == false[.](#17.sentence-1)
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11919)
|
||||
|
||||
*Returns*:
|
||||
|
||||
- [(18.1)](#18.1)
|
||||
|
||||
future::get() returns the value v stored in the object's shared state asstd::move(v)[.](#18.1.sentence-1)
|
||||
|
||||
- [(18.2)](#18.2)
|
||||
|
||||
future<R&>::get() returns the reference stored as value in the object's shared state[.](#18.2.sentence-1)
|
||||
|
||||
- [(18.3)](#18.3)
|
||||
|
||||
future<void>::get() returns nothing[.](#18.3.sentence-1)
|
||||
|
||||
[19](#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[.](#19.sentence-1)
|
||||
|
||||
[ð](#lib:valid,future)
|
||||
|
||||
`bool valid() const noexcept;
|
||||
`
|
||||
|
||||
[20](#20)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11944)
|
||||
|
||||
*Returns*: true only if *this refers to a shared state[.](#20.sentence-1)
|
||||
|
||||
[ð](#lib:wait,future)
|
||||
|
||||
`void wait() const;
|
||||
`
|
||||
|
||||
[21](#21)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11955)
|
||||
|
||||
*Effects*: Blocks until the shared state is ready[.](#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](#22)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11968)
|
||||
|
||||
*Effects*: None if the shared state contains a deferred function ([[futures.async]](futures.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[.](#22.sentence-1)
|
||||
|
||||
[23](#23)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L11976)
|
||||
|
||||
*Returns*:
|
||||
|
||||
- [(23.1)](#23.1)
|
||||
|
||||
future_status::deferred if the shared state contains a deferred
|
||||
function[.](#23.1.sentence-1)
|
||||
|
||||
- [(23.2)](#23.2)
|
||||
|
||||
future_status::ready if the shared state is ready[.](#23.2.sentence-1)
|
||||
|
||||
- [(23.3)](#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[.](#23.3.sentence-1)
|
||||
|
||||
[24](#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"))[.](#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](#25)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12001)
|
||||
|
||||
*Effects*: None if the shared state contains a deferred function ([[futures.async]](futures.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[.](#25.sentence-1)
|
||||
|
||||
[26](#26)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12009)
|
||||
|
||||
*Returns*:
|
||||
|
||||
- [(26.1)](#26.1)
|
||||
|
||||
future_status::deferred if the shared state contains a deferred
|
||||
function[.](#26.1.sentence-1)
|
||||
|
||||
- [(26.2)](#26.2)
|
||||
|
||||
future_status::ready if the shared state is ready[.](#26.2.sentence-1)
|
||||
|
||||
- [(26.3)](#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[.](#26.3.sentence-1)
|
||||
|
||||
[27](#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"))[.](#27.sentence-1)
|
||||
Reference in New Issue
Block a user