命名空间
变体
操作

std::async

来自 cppreference.cn
< cpp‎ | thread
 
 
并发支持库
线程
(C++11)
(C++20)
this_thread 命名空间
(C++11)
(C++11)
(C++11)
协同取消
互斥
(C++11)
通用锁管理
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
条件变量
(C++11)
信号量
门闩和屏障
(C++20)
(C++20)
期值
(C++11)
(C++11)
async
(C++11)
(C++11)
安全回收
(C++26)
危险指针
原子类型
(C++11)
(C++20)
原子类型的初始化
(C++11)(C++20 中已弃用)
(C++11)(C++20 中已弃用)
内存排序
(C++11)(C++26 中已弃用)
原子操作的自由函数
原子标志的自由函数
 
在头文件 <future> 中定义
template< class F, class... Args >
std::future</* 见下文 */> async( F&& f, Args&&... args );
(1) (C++11 起)
template< class F, class... Args >

std::future</* 见下文 */> async( std::launch policy,

                                    F&& f, Args&&... args );
(2) (C++11 起)

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

1) 其行为如同调用 (2),其中 policystd::launch::async | std::launch::deferred
2) 根据特定的启动策略 policy(见下文),用参数 args 调用函数 f

std::async 的返回类型是 std::future<V>,其中 V

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

(C++17 前)

std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>.

(C++17 起)


如果满足以下任何条件,程序将不正确:

(C++20 前)

如果以下任一条件为 false,则程序格式错误

(C++20 起)

std::async 的调用与对 f 的调用 同步,并且 f 的完成 先于 共享状态的就绪。

目录

[编辑] 参数

f - 要调用的 可调用(Callable)对象
args - 传递给 f 的参数
policy - 位掩码值,其中各个位控制允许的执行方法

[编辑] 返回值

std::future,引用此 std::async 调用创建的共享状态。

[编辑] 启动策略

[编辑] 异步调用

如果设置了 async 标志,即 (policy & std::launch::async) != 0,则 std::async 调用

INVOKE(decay-copy(std::forward<F>(f)),
       decay-copy(std::forward<Args>(args))...)

(直至 C++23)

std::invoke(auto(std::forward<F>(f)),
            auto(std::forward<Args>(args))...)

(C++23 起)

如同在一个由 std::thread 对象表示的新执行线程中。

decay-copy 的调用在当前线程中求值。

(直至 C++23)

auto 产生的值在当前线程中 实体化

(C++23 起)

如果函数 f 返回一个值或抛出异常,它将存储在通过 std::async 返回给调用者的 std::future 可访问的共享状态中。

[编辑] 延迟调用

如果设置了 deferred 标志(即 (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 起)

执行延迟求值(Lazy evaluation)

  • std::async 返回给调用者的 std::future 的非定时等待函数的第一次调用将在调用等待函数的线程(不必是最初调用 std::async 的线程)中评估 INVOKE(std::move(g), std::move(xyz)),其中
(直至 C++23)
(C++23 起)
  • 结果或异常被放置在与返回的 std::future 关联的共享状态中,然后才使其就绪。所有后续对相同 std::future 的访问都将立即返回结果。

[编辑] 其他策略

如果在 policy 中既没有设置 std::launch::async 也没有设置 std::launch::deferred,也没有设置任何实现定义的策略标志,则行为未定义。

[编辑] 策略选择

如果设置了多个标志,则选择哪种策略由实现定义。对于默认情况(std::launch::asyncstd::launch::deferred 标志都在 policy 中设置),标准建议(但不要求)利用可用的并发性,并延迟任何额外的任务。

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

  • 对共享由 std::async 调用创建的共享状态的异步返回对象上的等待函数的调用将阻塞,直到关联线程完成(如同已加入),或者超时;并且
  • 关联线程的完成与第一次等待共享状态的函数的成功返回,或与释放共享状态的最后一个函数的返回同步,以先发生者为准。

[编辑] 异常

抛出

[编辑] 注意

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

实现定义的启动策略示例包括同步策略(在 std::async 调用中立即执行)和任务策略(类似于 std::async,但线程局部变量不清空)

如果从 std::async 获取的 std::future 未被移动或绑定到引用,则 std::future 的析构函数将在完整表达式的末尾阻塞,直到异步操作完成,从而使以下代码本质上同步

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

请注意,通过调用 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 << "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

可能的输出

The sum is 10000
43
world!
53
Hello 42

[编辑] 缺陷报告

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

缺陷报告 应用于 发布时的行为 正确的行为
LWG 2021 C++11 返回类型不正确且在延迟情况下参数的
值类别不明确
已更正返回类型并
澄清使用右值
LWG 2078 C++11 不清楚如果 policy 指定了除了 std::launch::async 之外的其他启动策略,
是否会抛出 std::system_error
只有当 policystd::launch::async 时才可能抛出
仅当
policy == std::launch::async 时才抛出
LWG 2100 C++11 定时等待函数无法超时
如果使用 std::launch::async 策略
允许
LWG 2120 C++11 如果未设置标准
或实现定义的策略,则行为不明确
在这种情况下,行为是
未定义的
LWG 2186 C++11 不清楚延迟求值返回的值和抛出的
异常如何处理
它们存储在
共享状态中
LWG 2752 C++11 如果无法分配内部数据结构的内存,std::async 可能不会抛出 std::bad_alloc
如果无法分配内部数据结构的内存
抛出
LWG 3476 C++20 (衰变后的) F 类型和参数类型
曾被直接要求为可移动构造的
已移除这些要求[1]
  1. 可移动构造性已经通过 std::is_constructible_v 间接要求。

[编辑] 另见

(C++11)
等待一个异步设置的值
(类模板) [编辑]
C++ 文档 for 执行支持库