Scroll to navigation

std::async(3) C++ Standard Libary std::async(3)

NAME

std::async - std::async

Synopsis


Defined in header <future>
template< class F, class... Args >
(since
std::future<typename std::result_of<typename C++11)
std::decay<F>::type( (until
typename std::decay<Args>::type...)>::type> C++17)


async( F&& f, Args&&... args );
template< class F, class... Args >
(since
std::future<std::invoke_result_t<std::decay_t<F>, C++17)
std::decay_t<Args>...>> (until
C++20)
async( F&& f, Args&&... args );
template< class F, class... Args >


[[nodiscard]]
std::future<std::invoke_result_t<std::decay_t<F>, (since
C++20)
std::decay_t<Args>...>>


async( F&& f, Args&&... args ); (1)
template< class F, class... Args >
(since
std::future<typename std::result_of<typename C++11)
std::decay<F>::type( (until
typename std::decay<Args>::type...)>::type> C++17)


async( std::launch policy, F&& f, Args&&... args );
template< class F, class... Args >
(since
std::future<std::invoke_result_t<std::decay_t<F>, C++17)
std::decay_t<Args>...>> (2) (until
C++20)
async( std::launch policy, F&& f, Args&&... args );
template< class F, class... Args >


[[nodiscard]]
std::future<std::invoke_result_t<std::decay_t<F>, (since
C++20)
std::decay_t<Args>...>>


async( std::launch policy, F&& f, Args&&... args );


The function template std::async runs the function f asynchronously (potentially in
a separate thread which might be a part of a thread pool) and returns a std::future
that will eventually hold the result of that function call.


1) Behaves as if (2) is called with policy being std::launch::async |
std::launch::deferred.
2) Calls a function f with arguments args according to a specific launch policy
policy (see below).


If any of the following conditions is satisfied, the program is
ill-formed:


* F is not MoveConstructible. (until C++20)
* Any type in Args is not MoveConstructible.
* INVOKE(decay-copy(std::forward<F>(f)),
decay-copy(std::forward<Args>(args))...) is not a valid
expression.
If any of the following is false, the program is ill-formed:


* std::is_constructible_v<std::decay_t<F>, F> (since C++20)
* (std::is_constructible_v<std::decay_t<Args>, Args> && ...)
* std::is_invocable_v<std::decay_t<F>, std::decay_t<Args>...>


The call to std::async synchronizes with the call to f, and the completion of f is
sequenced before making the shared state ready.

Parameters


f - Callable object to call
args - parameters to pass to f
policy - bitmask value, where individual bits control the allowed methods of
execution

Return value


std::future referring to the shared state created by this call to std::async.


Launch policies


Async invocation


If the async flag is set (i.e. (policy & std::launch::async) != 0), then


std::async calls INVOKE(decay-copy(std::forward<F>(f)),
decay-copy(std::forward<Args>(args))...) as if in a new thread (until C++23)
of execution represented by a std::thread object.
std::async calls std::invoke(auto(std::forward<F>(f)),
auto(std::forward<Args>(args))...) as if in a new thread (since C++23)
of execution represented by a std::thread object.


The calls of decay-copy are evaluated
(until C++23)
The values produced by auto are materialized
(since C++23) in the current thread. If the function f returns a value or throws an
exception, it is stored in the shared state accessible through the std::future that
std::async returns to the caller.


Deferred invocation


If the deferred flag is set (i.e. (policy & std::launch::deferred) != 0), then
std::async stores
decay-copy(std::forward<F>(f)) and decay-copy(std::forward<Args>(args))...
(until C++23)
auto(std::forward<F>(f)) and auto(std::forward<Args>(args))...
(since C++23) in the shared state.


Lazy evaluation is performed:


* The first call to a non-timed wait function on the std::future that std::async
returned to the caller will evaluate INVOKE(std::move(g), std::move(xyz)) in the
current thread (which does not have to be the thread that originally called
std::async), where


* g is the stored value of
decay-copy(std::forward<F>(f))
(until C++23)
auto(std::forward<F>(f))
(since C++23) and
* xyz is the stored copy of
decay-copy(std::forward<Args>(args))...
(until C++23)
auto(std::forward<Args>(args))...
(since C++23).
* The result or exception is placed in the shared state associated with the
returned std::future and only then it is made ready. All further accesses to the
same std::future will return the result immediately.


Other policies


If neither std::launch::async nor std::launch::deferred, nor any
implementation-defined policy flag is set in policy, the behavior is undefined.


Policy selection


If more than one flag is set, it is implementation-defined which policy is selected.
For the default (both the std::launch::async and std::launch::deferred flags are set
in policy), standard recommends (but does not require) utilizing available
concurrency, and deferring any additional tasks.


If the std::launch::async policy is chosen,


* a call to a waiting function on an asynchronous return object that shares the
shared state created by this std::async call blocks until the associated thread
has completed, as if joined, or else time out; and
* the associated thread completion synchronizes-with the successful return from
the first function that is waiting on the shared state, or with the return of
the last function that releases the shared state, whichever comes first.

Exceptions


Throws


* std::bad_alloc, if the memory for the internal data structures cannot be
allocated, or
* std::system_error with error condition
std::errc::resource_unavailable_try_again, if policy == std::launch::async and
the implementation is unable to start a new thread.
* If policy is std::launch::async | std::launch::deferred or has additional
bits set, it will fall back to deferred invocation or the
implementation-defined policies in this case.

Notes


The implementation may extend the behavior of the first overload of std::async by
enabling additional (implementation-defined) bits in the default launch policy.


Examples of implementation-defined launch policies are the sync policy (execute
immediately, within the std::async call) and the task policy (similar to std::async,
but thread-locals are not cleared)


If the std::future obtained from std::async is not moved from or bound to a
reference, the destructor of the std::future will block at the end of the full
expression until the asynchronous operation completes, essentially making code such
as the following synchronous:


std::async(std::launch::async, []{ f(); }); // temporary's dtor waits for f()
std::async(std::launch::async, []{ g(); }); // does not start until f() completes


Note that the destructors of std::futures obtained by means other than a call to
std::async never block.

Example

// Run this code


#include <algorithm>
#include <future>
#include <iostream>
#include <mutex>
#include <numeric>
#include <string>
#include <vector>


std::mutex m;


struct X
{
void foo(int i, const std::string& str)
{
std::lock_guard<std::mutex> lk(m);
std::cout << str << ' ' << i << '\n';
}


void bar(const std::string& str)
{
std::lock_guard<std::mutex> lk(m);
std::cout << str << '\n';
}


int operator()(int i)
{
std::lock_guard<std::mutex> lk(m);
std::cout << i << '\n';
return i + 10;
}
};


template<typename RandomIt>
int parallel_sum(RandomIt beg, RandomIt end)
{
auto len = end - beg;
if (len < 1000)
return std::accumulate(beg, end, 0);


RandomIt mid = beg + len / 2;
auto handle = std::async(std::launch::async,
parallel_sum<RandomIt>, mid, end);
int sum = parallel_sum(beg, mid);
return sum + handle.get();
}


int main()
{
std::vector<int> v(10000, 1);
std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';


X x;
// Calls (&x)->foo(42, "Hello") with default policy:
// may print "Hello 42" concurrently or defer execution
auto a1 = std::async(&X::foo, &x, 42, "Hello");
// Calls x.bar("world!") with deferred policy
// prints "world!" when a2.get() or a2.wait() is called
auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
// Calls X()(43); with async policy
// prints "43" concurrently
auto a3 = std::async(std::launch::async, X(), 43);
a2.wait(); // prints "world!"
std::cout << a3.get() << '\n'; // prints "53"
} // if a1 is not done at this point, destructor of a1 prints "Hello 42" here

Possible output:


The sum is 10000
43
world!
53
Hello 42


Defect reports


The following behavior-changing defect reports were applied retroactively to
previously published C++ standards.


DR Applied to Behavior as published Correct behavior
return type incorrect and value corrected return type and
LWG 2021 C++11 category clarified that rvalues are
of arguments unclear in the deferred used
case
it was unclear whether
std::system_error can only be thrown if
LWG 2078 C++11 may be thrown if policy specifies policy ==
other std::launch::async
launch policies besides
std::launch::async
timed waiting functions could not
LWG 2100 C++11 timeout allowed
if std::launch::async policy is used
the behavior was unclear if no
LWG 2120 C++11 standard the behavior is
or implementation-defined policy is undefined in this case
set
std::async might not throw
LWG 2752 C++11 std::bad_alloc if the throws
memory for the internal data
structures cannot be allocated
(the decayed types of) F and the
LWG 3476 C++20 argument types removed these
were directly required to be move requirements^[1]
constructible


1. ↑ The move-constructibility is already indirectly required by
std::is_constructible_v.

See also


future waits for a value that is set asynchronously
(C++11) (class template)

2024.06.10 http://cppreference.com