Files
cppdraft_translate/cppdraft/futures/async.md
2025-10-25 03:02:53 +03:00

191 lines
7.6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.5invoke functions"), [[thread.thread.constr]](thread.thread.constr "32.4.3.3Constructors"))
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.5Temporary 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.9Function 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.5Shared 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.6Members"));
- [(4.2)](#4.2)
the associated thread completion[synchronizes with](intro.multithread#def:synchronize_with "6.10.2Multi-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*]