std::async
- cppreference
std::async
- cppreference
1. std::async
Defined in header <future>
async
(C++11)
runs a function asynchronously (potentially in a new thread) and returns a std::future
that will hold the result (function template)。
异步运行一个函数 (有可能在新线程中执行),并返回保有其结果的 std::future
(函数模板)。
potentially [pəˈtenʃəli]:adv. 可能地,潜在地
header [ˈhedə(r)]:n. 头球,页眉,数据头,收割台
1.1 since C++11 - until C++17
template <class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
async( Function&& f, Args&&... args );
1.2 since C++17 - until C++20
template <class Function, class... Args>
std::future<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>>
async( Function&& f, Args&&... args );
1.3 since C++20
template <class Function, class... Args>
[[nodiscard]]
std::future<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>>
async( Function&& f, Args&&... args );
1.4 since C++11 - until C++17
template <class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
async( std::launch policy, Function&& f, Args&&... args );
1.5 since C++17 - until C++20
template <class Function, class... Args>
std::future<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>>
async( std::launch policy, Function&& f, Args&&... args );
1.6 since C++20
template <class Function, class... Args>
[[nodiscard]]
std::future<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>>
async( std::launch policy, Function&& f, Args&&... args );
defer [dɪˈfɜː(r)]:vi. 推迟,延期,服从 vt. 使推迟,使延期
asynchronous [eɪˈsɪŋkrənəs]:adj. 异步的,不同时的,不同期的
The template function async
runs the function f
asynchronously (potentially in a separate thread which may be part of a thread pool) and returns a std::future
that will eventually hold the result of that function call.
模板函数 async
异步地运行函数 f
(潜在地在可能是线程池一部分的分离线程中),并返回最终将保有该函数调用结果的 std::future
。
-
Behaves as if (2) is called with
policy
beingstd::launch::async | std::launch::deferred
. In other words,f
may be executed in another thread or it may be run synchronously when the resultingstd::future
is queried for a value.
表现如同以policy
为std::launch::async | std::launch::deferred
调用 (2)。换言之,f
可能执行于另一线程,或者它可能在查询产生的std::future
的值时同步运行。 -
Calls a function
f
with argumentsargs
according to a specific launch policypolicy
:
按照特定的执行策略policy
,以参数args
调用函数f
:
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.
若设置 async
标志 (即 (policy & std::launch::async) != 0
),则 async
在新的执行线程 (初始化所有线程局域对象后) 执行可调用对象 f
,如同产出 std::thread(std::forward<F>(f), std::forward<Args>(args)...)
,除了若 f
返回值或抛出异常,则于可通过 async
返回给调用方的 std::future
访问的共享状态存储结果。
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.
若设置 deferred
标志 (即 (policy & std::launch::deferred) != 0)
),则 async
以同 std::thread
构造函数的方式转换 f
与 args...
,但不产出新的执行线程。而是进行惰性求值:在 async
所返回的 std::future
上首次调用非定时等待函数,将导致在当前线程 (不必是最初调用 std::async
的线程) 中,以 args...
(作为右值传递) 的副本调用 f
(亦作为右值) 的副本。将结果或异常置于关联到该 future
的共享状态,然后才令它就绪。对同一 std::future
的所有后续访问都会立即返回结果。
If both the std::launch::async
and std::launch::deferred
flags are set in policy, it is up to the implementation whether to perform asynchronous execution or lazy evaluation.
若 policy
中设置了 std::launch::async
和 std::launch::deferred
两个标志,则进行异步执行还是惰性求值取决于实现。
If neither std::launch::async
nor std::launch::deferred
, nor any implementation-defined policy flag is set in policy, the behavior is undefined. (since C++14)
若 policy
中未设置 std::launch::async
或 std::launch::deferred
或任何实现定义策略标志,则行为未定义。
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.
任何情况下,对 std::async
的调用同步于 (定义于 std::memory_order
) 对 f
的调用,且 f
的完成先序于令共享状态就绪。若选择 async
策略,则关联线程的完成同步于首个等待于共享状态上的函数的成功返回,或最后一个释放共享状态的函数的返回,两者的先到来者。
2. Parameters - 参数
f
- Callable object to call (要调用的可调用 (callable) 对象)
args...
- parameters to pass to f
(传递给 f
的参数)
policy
- bitmask value, where individual bits control the allowed methods of execution (位掩码值,每个单独位控制允许的执行方法)
Bit (位) - Explanation (解释)
std::launch::async
- enable asynchronous evaluation (启用异步求值)
std::launch::deferred
- enable lazy evaluation (启用惰性求值)
async [əˈsɪŋk]:abbr. 异步,非同步 (asynchronous)
2.1 Type requirements - 类型要求
Function
, Args
must meet the requirements of MoveConstructible.
Function
, Args
必须满足可移动构造 (MoveConstructible) 的要求。
3. Return value - 返回值
std::future
referring to the shared state created by this call to std::async
.
指代此次调用 std::async
所创建的共享状态的 std::future
。
4. 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.
若运行策略等于 std::launch::async
且实现无法开始新线程 (该情况下,若运行策略为 async|deferred
或设置了额外位,则它将回退到 deferred
或实现定义的策略),则抛出以 std::errc::resource_unavailable_try_again
为错误条件的 std::system_error
,或者若无法分配内部数据结构所用的内存,则为 std::bad_alloc
。
5. 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.
实现可以通过在默认运行策略中启用额外 (实现定义的) 位,扩展 std::async
第一重载的行为。
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)
实现定义的运行策略的例子是同步策略 (在 async
调用内立即执行) 和任务策略 (类似 async,但不清理线程局域对象)。
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::future
未被移动或绑定到引用,则在完整表达式结尾,std::future
的析构函数将阻塞直至异步计算完成,实质上令如下代码同步:
std::async(std::launch::async, []{ f(); }); // temporary's dtor waits for f() - 临时量的析构函数等待 f()
std::async(std::launch::async, []{ g(); }); // does not start until f() completes - f() 完成前不开始
(note that the destructors of std::futures
obtained by means other than a call to std::async
never block)
(注意,以调用 std::async
以外的方式获得的 std::future
的析构函数决不阻塞)
6. Defect reports - 缺陷报告
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
retroactively [ˌretroʊˈæktɪvli]:adv. 追溯地,逆动地
7. Example
//============================================================================
// Name : std::async
// Author : Yongqiang Cheng
// Version : Version 1.0.0
// Copyright : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================
#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"
return 0;
} // if a1 is not done at this point, destructor of a1 prints "Hello 42" here
22:18:58 **** Build of configuration Debug for project hello_world ****
make all
Building file: ../src/hello_world.cpp
Invoking: GCC C++ Compiler
g++ -std=c++1y -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/hello_world.d" -MT"src/hello_world.o" -o "src/hello_world.o" "../src/hello_world.cpp"
Finished building: ../src/hello_world.cpp
Building target: hello_world
Invoking: GCC C++ Linker
g++ -o "hello_world" ./src/hello_world.o
./src/hello_world.o: In function `std::thread::thread<std::__future_base::_Async_state_impl<std::_Bind_simple<std::_Mem_fn<void (X::*)(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)> (X, char const*)>, void>::_Async_state_impl(std::_Bind_simple<std::_Mem_fn<void (X::*)(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)> (X, char const*)>&&)::{lambda()#1}>(std::__future_base::_Async_state_impl<std::_Bind_simple<std::_Mem_fn<void (X::*)(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)> (X, char const*)>, void>::_Async_state_impl(std::_Bind_simple<std::_Mem_fn<void (X::*)(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)> (X, char const*)>&&)::{lambda()#1}&&)':
/usr/include/c++/5/thread:137: undefined reference to `pthread_create'
./src/hello_world.o: In function `std::thread::thread<std::__future_base::_Async_state_impl<std::_Bind_simple<X (int)>, int>::_Async_state_impl(std::_Bind_simple<X (int)>&&)::{lambda()#1}>(std::__future_base::_Async_state_impl<std::_Bind_simple<X (int)>, int>::_Async_state_impl(std::_Bind_simple<X (int)>&&)::{lambda()#1}&&)':
/usr/include/c++/5/thread:137: undefined reference to `pthread_create'
./src/hello_world.o: In function `std::thread::thread<std::__future_base::_Async_state_impl<std::_Bind_simple<int (*(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >))(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >)>, int>::_Async_state_impl(std::_Bind_simple<int (*(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >))(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >)>&&)::{lambda()#1}>(std::__future_base::_Async_state_impl<std::_Bind_simple<int (*(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >))(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >)>, int>::_Async_state_impl(std::_Bind_simple<int (*(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >))(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >)>&&)::{lambda()#1}&&)':
makefile:45: recipe for target 'hello_world' failed
/usr/include/c++/5/thread:137: undefined reference to `pthread_create'
./src/hello_world.o: In function `std::thread::thread<std::__future_base::_Async_state_impl<std::_Bind_simple<std::_Mem_fn<void (X::*)(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)> (X*, int, char const*)>, void>::_Async_state_impl(std::_Bind_simple<std::_Mem_fn<void (X::*)(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)> (X*, int, char const*)>&&)::{lambda()#1}>(std::__future_base::_Async_state_impl<std::_Bind_simple<std::_Mem_fn<void (X::*)(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)> (X*, int, char const*)>, void>::_Async_state_impl(std::_Bind_simple<std::_Mem_fn<void (X::*)(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)> (X*, int, char const*)>&&)::{lambda()#1}&&)':
/usr/include/c++/5/thread:137: undefined reference to `pthread_create'
collect2: error: ld returned 1 exit status
make: *** [hello_world] Error 1
22:19:00 Build Finished (took 2s.274ms)
undefined reference to pthread_create
Project -> properties -> C/C++ Build -> Settings -> Tool Settings -> GCC C++ Linker -> Libraries (-l
) 添加 pthread
参数。
Possible output
The sum is 10000
world!
43
53