C++11新特性:多线程管理 std::async
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 负责任务结果的传递,确保任务执行的安全与可控性。