std::async

来自cppreference.com
< cpp‎ | thread
 
 
并发支持库
线程
(C++11)
(C++20)
(C++20)
this_thread 命名空间
(C++11)
(C++11)
(C++11)
原子类型
(C++11)
(C++20)
原子类型的初始化
(C++11)(C++20 中弃用)
(C++11)(C++20 中弃用)
原子操作的自由函数
原子标志的自由函数
内存序
互斥
(C++11)
通用锁管理
(C++11)
(C++11)
(C++11)
(C++11)(C++11)(C++11)
(C++11)
(C++11)
条件变量
(C++11)
信号量
闩与屏障
(C++20)
(C++20)
future
(C++11)
(C++11)
async
(C++11)
(C++11)
 
在标头 <future> 定义
(1)
template< class Function, class... Args >

std::future<typename std::result_of<typename std::decay<Function>::type(
        typename std::decay<Args>::type...)>::type>

    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 起)
(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 );
(C++20 起)
(2)
template< class Function, class... Args >

std::future<typename std::result_of<typename std::decay<Function>::type(
        typename std::decay<Args>::type...)>::type>

    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 起)
(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 );
(C++20 起)

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

1) 表现如同以 std::launch::async | std::launch::deferred 作为 policy 调用 (2)
2) 按照特定的启动策略 policy(见下文),以参数 args 调用函数 f

任何情况下,对 std::async 的调用同步于(定义见 std::memory_order)对 f 的调用,且 f 的完成先序于令共享状态就绪。

如果 INVOKE(decay-copy(std::forward<F>(f)),
       decay-copy(std::forward<Args>(args))...)
不是合法表达式,那么程序非良构。

(C++20 前)

在满足以下任一条件时,程序非良构:

(C++20 起)

参数

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

返回值

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

启动策略

异步调用

如果有设置异步 标志(即 (policy & std::launch::async) != 0),那么

std::async 会如同在一个新的以某个 std::thread 对象表示的执行线程中调用 INVOKE(decay-copy(std::forward<F>(f)),
       decay-copy(std::forward<Args>(args))...)

(C++23 前)

std::async 会如同在一个新的以某个 std::thread 对象表示的执行线程中调用 std::invoke(auto(std::forward<F>(f)),
            auto(std::forward<Args>(args))...)

(C++23 起)

decay-copy 的调用在当前线程求值 (C++23 前)auto 产生的值在当前线程实质化 (C++23 起)。如果 f 返回值或抛出异常,那么它们会存储到 std::async 返回给调用方的 std::future 的共享状态中。

推迟调用

如果有设置推迟 标志(即 (policy & std::launch::deferred) != 0),那么 std::async 会将 decay-copy(std::forward<F>(f))decay-copy(std::forward<Args>(args))... (C++23 前)auto(std::forward<F>(f))auto(std::forward<Args>(args))... (C++23 起) 存储到共享状态中。

进行惰性求值

  • std::async 返回给调用方的 std::future 上首次调用非定时等待函数会在当前线程(不一定是最初调用 std::async 的线程)中求值 INVOKE(std::move(g), std::move(xyz)),其中
  • 将结果或异常置于关联到该 std::future 的共享状态,然后才令它就绪。对同一 std::future 的所有后续访问都会立即返回结果。

其他策略

如果 policy 中没有设置 std::launch::asyncstd::launch::deferred 或任何由实现定义的其他策略标志,那么行为未定义。

策略选择

如果 policy 中设置了多个标志,那么由实现定义选择哪个策略。对于默认情况(policy 中同时设置了 std::launch::asyncstd::launch::deferred 两个标志),标准建议(但不要求)利用现有的并发资源,并且推迟另外的任务。

如果选择了 std::launch::async 策略,那么:

  • 对于共享该 std::async 创建的共享状态的某个异步返回对象,对它的等待函数的调用会阻塞,直到关联的线程如同以结束执行或超时的方式完成。
  • 关联线程的完成同步于 首个在共享状态上等待的函数的成功返回和最后一个释放共享状态的函数的返回,两者中的先到来的一方。

异常

可能会抛出以下异常:

注解

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

由实现定义的启动策略的例子是同步策略(在 std::async 调用内立即执行)和任务策略(类似 std::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 的析构函数不会阻塞。

示例

#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 << "和为 " << parallel_sum(v.begin(), v.end()) << '\n';
 
    X x;
    // 以默认策略调用 x.foo(42, "Hello") :
    // 可能同时打印 "Hello 42" 或延迟执行
    auto a1 = std::async(&X::foo, &x, 42, "Hello");
    // 以 deferred 策略调用 x.bar("world!")
    // 调用 a2.get() 或 a2.wait() 时打印 "world!"
    auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
    // 以 async 策略调用 X()(43) :
    // 同时打印 "43"
    auto a3 = std::async(std::launch::async, X(), 43);
    a2.wait();                     // 打印 "world!"
    std::cout << a3.get() << '\n'; // 打印 "53"
} // 若 a1 在此点未完成,则 a1 的析构函数在此打印 "Hello 42"

可能的输出:

和为 10000
43
world!
53
Hello 42

缺陷报告

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

缺陷报告 应用于 出版时的行为 正确行为
LWG 2021 C++11 返回类型不正确, deferred 的情况下参数的值类别不明 更正返回类型,明确使用右值
LWG 2078 C++11 不明确 policy 在除 std::launch::async 外还指定了
其他启动策略时是否会抛出 std::system_error
仅限
policy == std::launch::async
LWG 2100 C++11 使用 std::launch::async 策略时计时等待函数不能超时 可以超时
LWG 2120 C++11 未设置标准或实现定义的策略的情况下行为不明 行为未定义
LWG 2752 C++11 std::async 在无法分配内部数据结构所用的
内存时不一定会抛出 std::bad_alloc
会抛出
LWG 3476 C++11 要求 FunctionArgs... 可移动构造 (MoveConstructible)
但没有指定的额外移动构造
移除要求