Namespaces
Variants

std:: async

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
async
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
定义于头文件 <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 ,该对象最终将保存该函数调用的结果。

1) 行为如同以 policy std:: launch :: async | std:: launch :: deferred 调用 (2)
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 - 要调用的 可调用 对象
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 起)

惰性求值 被执行:

  • 对由 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::async std::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(); }); // 临时对象的析构函数等待 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 << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';
    X x;
    // 以默认策略调用 (&x)->foo(42, "Hello"):
    // 可能并发打印 "Hello 42" 或延迟执行
    auto a1 = std::async(&X::foo, &x, 42, "Hello");
    // 以延迟策略调用 x.bar("world!")
    // 在调用 a2.get() 或 a2.wait() 时打印 "world!"
    auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
    // 以异步策略调用 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"

可能的输出:

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 不明确
仅当
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++ 文档 中关于 执行支持库 的内容