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
负责任务结果的传递,确保任务执行的安全与可控性。
发表回复