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*]
|
||||
Reference in New Issue
Block a user