Scroll to navigation

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

NAME

std::async - std::async

Synopsis


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


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


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


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


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


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


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


The function template 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.


* If the async flag is set (i.e. (policy & std::launch::async) != 0),
then async executes the callable object f on a new thread of execution
(with all thread-locals initialized) as if spawned by
std::thread(std::forward<F>(f), std::forward<Args>(args)...), except
that if the function f returns a value or throws an exception, it is
stored in the shared state accessible through the std::future that
async returns to the caller.
* If the deferred flag is set (i.e. (policy & std::launch::deferred) !=
0), then async converts f and args... the same way as by std::thread
constructor, but does not spawn a new thread of execution. Instead,
lazy evaluation is performed: the first call to a non-timed wait
function on the std::future that async returned to the caller will
cause the copy of f to be invoked (as an rvalue) with the copies of
args... (also passed as rvalues) in the current thread (which does not
have to be the thread that originally called std::async). The result or
exception is placed in the shared state associated with the future and
only then it is made ready. All further accesses to the same
std::future will return the result immediately.
* If neither std::launch::async nor std::launch::deferred, nor any
implementation-defined policy flag is set in policy, the behavior is
undefined.


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 doesn't require) utilizing available
concurrency, and deferring any additional tasks.


In any case, the call to std::async synchronizes-with (as defined in
std::memory_order) the call to f, and the completion of f is sequenced-before making
the shared state ready. If the async policy is chosen, 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. If std::decay<Function>::type or each type
in std::decay<Args>::type is not constructible from its corresponding argument, the
program is ill-formed.

Parameters


f - Callable object to call
args... - parameters to pass to f
bitmask value, where individual bits control the allowed methods of
execution
policy -
Bit Explanation
std::launch::async enable asynchronous evaluation
std::launch::deferred enable lazy evaluation

Return value


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

Exceptions


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

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 async call) and the task policy (similar to 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 <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future>
#include <string>
#include <mutex>


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
corrected return type
LWG 2021 C++11 return type incorrect and value category and
of arguments unclear in the deferred case clarified that rvalues
are used
the behavior was unclear if no standard the behavior is
LWG 2120 C++11 or undefined
implementation-defined policy is set
Function and Args... were required to be
LWG 3476 C++11 MoveConstructible requirements removed
while no additional move constructions
specified

See also


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

2022.07.31 http://cppreference.com