std::async

来自cppreference.com
< cpp‎ | thread
定义于头文件 <future>
(1)
template< class Function, class... Args>

std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>

    async( Function&& f, Args&&... args );
(C++11 起)
(C++17 前)
template< class Function, class... Args>

std::future<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>>

    async( Function&& f, Args&&... args );
(C++17 起)
(2)
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 );
(C++11 起)
(C++17 前)
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 );
(C++17 起)

模板函数 async 异步地运行函数 f (潜在地在可能是线程池一部分的分离线程中),并返回最终将保有该函数调用结果的 std::future

1) 表现如同以 policystd::launch::async | std::launch::deferred 调用 (2) 。换言之, f 可能执行于另一线程,或者它可能在查询产生的 std::future 的值时同步运行。
2) 按照特定的执行策略 policy ,以参数 args 调用函数 f
  • 若设置 async 标志(即 (policy & std::launch::async) != 0 ),则 async 在新的执行线程(初始化所有线程局域对象后)执行可调用对象 f ,如同产出 std::thread(std::forward<F>(f), std::forward<Args>(args)...) ,除了若 f 返回值或抛出异常,则于可通过 async 返回给调用方的 std::future 访问的共享状态存储结果。
  • 若设置 deferred 标志(即 (policy & std::launch::deferred) != 0 ),则 async 以同 std::thread 构造函数的方式转换 fargs... ,但不产出新的执行线程。而是进行惰性求值:在 async 所返回的 std::future 上首次调用非定时等待函数,将导致在当前线程(不必是最初调用 std::async 的线程)中,以 args... (作为右值传递)的副本调用 f (亦作为右值)的副本。将结果或异常置于关联到该 future 的共享状态,然后才令它就绪。对同一 std::future 的所有后续访问都会立即返回结果。
  • policy 中设置了 std::launch::asyncstd::launch::deferred 两个标志,则进行异步执行还是惰性求值取决于实现。
  • policy 中未设置 std::launch::asyncstd::launch::deferred 或任何实现定义策略标志,则行为未定义。
(C++14 起)

任何情况下,对 std::async 的调用同步于(定义于 std::memory_order )对 f 的调用,且 f 的完成先序于令共享状态就绪。若选择 async 策略,则关联线程的完成同步于首个等待于共享状态上的函数的成功返回,或最后一个释放共享状态的函数的返回,两者的先到来者。

目录

[编辑] 参数

f - 要调用的可调用 (Callable) 对象
args... - 传递给 f 的参数
policy - 位掩码值,每个单独位控制允许的执行方法
解释
std::launch::async 启用异步求值
std::launch::deferred 启用惰性求值


类型要求
-
Function, Args 必须满足 MoveConstructible 的要求。

[编辑] 返回值

指代此次调用 std::async 所创建的共享状态的 std::future

[编辑] 异常

若运行策略等于 std::launch::async 且实现无法开始新线程(该情况下,若运行策略为 async|deferred 或设置了额外位,则它将回退到 deferred 或实现定义的策略),则抛出以 std::errc::resource_unavailable_try_again 为错误条件的 std::system_error ,或者若无法分配内部数据结构所用的内存,则为 std::bad_alloc

[编辑] 注意

实现可以通过在默认运行策略中启用额外(实现定义的)位,扩展 std::async 第一重载的行为。

实现定义的运行策略的例子是同步策略(在 async 调用内立即执行)和任务策略(类似 async ,但不清理线程局域对象)。

若从 std::async 获得的 std::future 未被移动或绑定到引用,则在完整表达式结尾, std::future 的析构函数将阻塞直至异步计算完成,实质上令如下代码同步:

std::async(std::launch::async, []{ f(); }); // 临时量的析构函数等待 f()
std::async(std::launch::async, []{ g(); }); // f() 完成前不开始

(注意,以调用 std::async 以外的方式获得的 std::future 的析构函数决不阻塞)

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR 应用于 出版时的行为 正确行为
LWG 2021 C++11 返回类型不正确, deferred 的情况下参数的值类别不明 更正返回类型,明确使用右值

[编辑] 示例

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future>
 
template <typename RAIter>
int parallel_sum(RAIter beg, RAIter end)
{
    auto len = end - beg;
    if (len < 1000)
        return std::accumulate(beg, end, 0);
 
    RAIter mid = beg + len/2;
    auto handle = std::async(std::launch::async,
                             parallel_sum<RAIter>, 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';
}

输出:

The sum is 10000