C++11 引入了许多新特性,其中之一是对多线程编程的支持。std::async 是 C++11 中一个强大的工具,用于简化多线程任务管理。本教程将带你了解 std::async 的基础知识,包括它与 std::future、std::promise、std::thread 的关系,以及常用的执行策略。通过简单的示例,我们会深入理解这些概念。
1. std::async 基本概念
std::async 允许我们以异步方式执行任务,并返回一个 std::future,用来获取任务的结果。它接受一个任务(即函数或 lambda 表达式)和参数,并决定是立即异步执行任务,还是推迟执行。
典型的 std::async 调用形式如下:
std::async(launch_policy, task, args...);
其中:
args...:传递给任务的参数。
launch_policy:执行策略(std::launch::async 或 std::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::async 或 std::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;
- 模板参数
Function和Args...:接收一个可调用对象(如函数、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::move 和 detach
std::thread([promise = std::move(promise), f = std::forward<Function>(f), args...]() mutable {
...
}).detach();
std::move:promise是一个独占对象,必须通过std::move传递给线程,确保它不会被复制。detach:线程分离,任务会在后台独立执行,主线程不会阻塞。
4. std::async 与 std::promise 和 std::future 的关系
std::promise是设置任务结果的工具,提供了set_value()和set_exception(),将结果或异常传递给future。std::future由promise.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::async 和 std::launch::deferred 提供了异步和推迟执行任务的灵活性。同时,std::promise 和 std::future 负责任务结果的传递,确保任务执行的安全与可控性。

发表回复