C++11新特性:多线程管理 std::async

C++11 引入了许多新特性,其中之一是对多线程编程的支持。std::async 是 C++11 中一个强大的工具,用于简化多线程任务管理。本教程将带你了解 std::async 的基础知识,包括它与 std::futurestd::promisestd::thread 的关系,以及常用的执行策略。通过简单的示例,我们会深入理解这些概念。

1. std::async 基本概念

std::async 允许我们以异步方式执行任务,并返回一个 std::future,用来获取任务的结果。它接受一个任务(即函数或 lambda 表达式)和参数,并决定是立即异步执行任务,还是推迟执行。

典型的 std::async 调用形式如下:

std::async(launch_policy, task, args...);

其中:

args...:传递给任务的参数。

launch_policy:执行策略(std::launch::asyncstd::launch::deferred)。

task:可执行的函数或 lambda 表达式。


2. 核心代码分析

我们将详细分析以下这段代码,它展示了如何根据不同的策略来执行任务:

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

// 如果是 deferred 模式,则任务在调用 get() 时才执行
if (policy == std::launch::deferred) {
return std::async_result<result_type>(std::bind(std::forward<Function>(f), std::forward<Args>(args)...));
}

// 如果是 async 模式,则启动新线程立即执行任务
else if (policy == std::launch::async) {
std::promise<result_type> promise;
std::future<result_type> future = promise.get_future();

// 创建新线程执行任务,并将结果存入 promise 中
std::thread([promise = std::move(promise), f = std::forward<Function>(f), args...]() mutable {
try {
promise.set_value(f(args...)); // 执行任务并设置值
} catch (...) {
promise.set_exception(std::current_exception()); // 捕获并传递异常
}
}).detach(); // detach 线程分离

return future;
}

throw std::invalid_argument("Invalid launch policy");
}

3. 代码详细解释

这段代码展示了 std::async 的基本实现,核心思想是根据不同的策略(std::launch::asyncstd::launch::deferred)来决定任务的执行方式。我们逐行解释其中的关键部分:

3.1 模板定义与 std::result_of
template<typename Function, typename... Args>
std::future<typename std::result_of<Function(Args...)>::type>
async(std::launch policy, Function&& f, Args&&... args) {
using result_type = typename std::result_of<Function(Args...)>::type;
  • 模板参数 FunctionArgs...:接收一个可调用对象(如函数、lambda)和多个参数。
  • std::result_of<Function(Args...)>::type:计算出 Function 函数调用的返回类型,作为 std::future 的模板参数 result_type
3.2 std::launch::deferred 策略
if (policy == std::launch::deferred) {
return std::async_result<result_type>(
std::bind(std::forward<Function>(f), std::forward<Args>(args)...)
);
}
  • std::launch::deferred 策略下,任务不会立即执行,而是被推迟到调用 future.get() 时才执行。这里通过 std::bind 将函数和参数绑定起来,创建一个延迟执行的任务。
3.3 std::launch::async 策略
else if (policy == std::launch::async) {
std::promise<result_type> promise;
std::future<result_type> future = promise.get_future();

std::thread([promise = std::move(promise), f = std::forward<Function>(f), args...]() mutable {
try {
promise.set_value(f(args...)); // 执行任务并设置返回值
} catch (...) {
promise.set_exception(std::current_exception()); // 捕获异常
}
}).detach(); // 分离线程

return future;
}
  • std::launch::async 策略下,任务会立即在新线程中执行。
    • std::promise:用于在异步任务中设置任务的返回值或异常。
    • std::future:从 promise 获取,可以在主线程中通过 future.get() 获取结果。
    • std::thread:创建一个新线程执行任务,并将 promise 的结果与异步任务的返回值绑定在一起。任务执行完毕后,promise.set_value 用于设置结果,或通过 set_exception 捕获并传递异常。
3.4 std::movedetach
std::thread([promise = std::move(promise), f = std::forward<Function>(f), args...]() mutable {
...
}).detach();
  • std::movepromise 是一个独占对象,必须通过 std::move 传递给线程,确保它不会被复制。
  • detach:线程分离,任务会在后台独立执行,主线程不会阻塞。

4. std::asyncstd::promisestd::future 的关系

  • std::promise 是设置任务结果的工具,提供了 set_value()set_exception(),将结果或异常传递给 future
  • std::futurepromise.get_future() 获取,能够异步地等待任务结果,通过 get() 获取值或异常。
  • std::thread 用于在异步策略下启动新线程,detach() 分离线程后,任务将在后台执行,不会影响主线程。

5. 完整示例

#include <iostream>
#include <future>
#include <thread>
#include <functional>
#include <stdexcept>

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

if (policy == std::launch::deferred) {
return std::async_result<result_type>(std::bind(std::forward<Function>(f), std::forward<Args>(args)...));
} else if (policy == std::launch::async) {
std::promise<result_type> promise;
std::future<result_type> future = promise.get_future();
std::thread([promise = std::move(promise), f = std::forward<Function>(f), args...]() mutable {
try {
promise.set_value(f(args...));
} catch (...) {
promise.set_exception(std::current_exception());
}
}).detach();
return future;
}

throw std::invalid_argument("Invalid launch policy");
}

int task(int x, int y) {
return x + y;
}

int main() {
std::future<int> result = async(std::launch::async, task, 3, 4);
std::cout << "Result: " << result.get() << std::endl;
return 0;
}

6. 总结

通过对 std::async 的内部实现进行剖析,我们可以看到它是如何根据不同的策略进行任务调度的。std::launch::asyncstd::launch::deferred 提供了异步和推迟执行任务的灵活性。同时,std::promisestd::future 负责任务结果的传递,确保任务执行的安全与可控性。


已发布

分类

来自

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注