在 C++11 中引入的 std::async是一个用于异步执行任务的工具,它简化了多线程编程的复杂度,通过返回 std::future对象实现对异步任务结果的获取。

​一、核心概念​

std::async用于启动一个异步任务(可能在独立线程中执行),并返回一个 std::future对象,通过该对象可以:

  • 阻塞等待任务完成并获取返回值(future::get());

  • 查询任务状态(future::valid()future::wait_for()等);

  • 异常传递(任务中的异常会延迟到 get()时抛出)。

​二、函数原型与启动策略​

std::async的声明如下:

template< class Function, class... Args >
std::future<typename std::result_of<Function(Args...)>::type>
    async( Function&& f, Args&&... args );

template< class Function, class... Args >
std::future<typename std::result_of<Function(Args...)>::type>
    async( std::launch policy, Function&& f, Args&&... args );

其中第二个模板参数是​​启动策略​​(std::launch枚举),控制任务的执行方式:

策略

说明

std::launch::async

强制在新线程中异步执行任务(类似 std::thread直接启动)。

std::launch::deferred

延迟执行:任务不会立即启动,直到调用 future.get()wait()时才在当前线程同步执行。

默认策略(无显式指定)

实现定义(通常是 `async

​三、基础用法示例​

​1. 最简用法(无显式策略)​
#include <iostream>
#include <future>
#include <thread>

int compute(int a, int b) {
    std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时操作
    return a + b;
}

int main() {
    // 启动异步任务,返回 std::future<int>
    auto future = std::async(compute, 2, 3); 

    // 主线程继续执行其他操作...
    std::cout << "Main thread working...";

    // 阻塞等待任务完成,获取结果
    int result = future.get(); 
    std::cout << "Result: " << result << std::endl; // 输出 5

    return 0;
}
  • std::async(compute, 2, 3)启动异步任务,传递函数 compute和参数 2, 3

  • future.get()阻塞主线程,直到任务完成并返回结果。

​2. 显式指定启动策略​
// 强制异步执行(新线程)
auto future_async = std::async(std::launch::async, compute, 2, 3);

// 延迟执行(当前线程同步执行)
auto future_deferred = std::async(std::launch::deferred, compute, 2, 3);

future_async.get(); // get()阻塞等待
future_deferred.get(); // 此时在当前线程同步执行 compute(2,3)

​四、参数传递与引用语义​

std::async支持传递任意可调用对象(函数、Lambda、函数对象等)和参数。若需传递引用,需用 std::ref包装:

#include <functional>

void modify(int& value) {
    value = 100;
}

int main() {
    int x = 0;
    // 错误:直接传递引用会被复制(值语义)
    // auto future = std::async(modify, x); 

    // 正确:用 std::ref 传递引用
    auto future = std::async(modify, std::ref(x)); 
    future.get();
    std::cout << x << std::endl; // 输出 100(x 被修改)

    return 0;
}

​五、std::future 的常用接口​

std::async返回的 std::future提供以下关键方法:

方法

说明

get()

阻塞直到任务完成,返回结果(或抛出任务中的异常);只能调用一次。

wait()

阻塞直到任务完成;可多次调用。

wait_for(timeout)

阻塞最多 timeout时间,返回 std::future_statusready/timeout/deferred)。

wait_until(timepoint)

阻塞直到指定时间点。

valid()

检查 future是否关联有效结果(未调用 get()时为 true)。

share()

转换为 std::shared_future(允许多个对象共享结果)。

​六、异常处理​

异步任务中抛出的异常会被 std::future捕获,直到调用 get()时重新抛出:

int risky_compute(int x) {
    if (x < 0) throw std::runtime_error("x is negative");
    return x * 2;
}

int main() {
    auto future = std::async(risky_compute, -1);
    try {
        int result = future.get(); // 抛出 std::runtime_error
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << ""; // 捕获异常
    }
    return 0;
}

​七、注意事项​

  1. ​生命周期管理​​:

    std::future析构时,若任务未完成且未被 get()wait(),可能导致程序终止(取决于实现)。若需共享结果,使用 std::shared_future

  2. ​线程复用​​:

    std::async不保证任务一定在新线程中执行(尤其是 deferred策略或编译器优化),依赖具体实现。

  3. ​性能开销​​:

    相比手动管理 std::threadstd::async自动管理线程生命周期,但频繁创建小任务可能有额外开销(适合中高耗时任务)。

​八、典型应用场景​

  • ​并行计算​​:同时执行多个独立任务(如图像处理中的多区域计算)。

  • ​异步IO​​:发起IO操作后异步等待结果,避免阻塞主线程。

  • ​任务编排​​:结合 std::future::wait_for实现超时控制(如监控任务是否超时)。

​总结​

std::async是 C++11 中简化异步编程的核心工具,通过 std::future提供结果获取和状态查询能力。合理使用其启动策略和异常处理机制,可有效提升代码的并发性能和可维护性。

惠州西湖

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐