1. C++11异步编程概览
核心概念与模型
在 C++11 中,异步执行指的是把耗时操作放到另外的执行上下文中进行,从而避免在主线程中阻塞。通过 未来对象(future)可以在操作完成时获取结果,且在等待期间可以继续执行其他工作。
模型层面,任务提交、执行、结果返回形成一个简单的数据流,使用 std::future 来表示未完成的结果,使用 std::async 来提交任务。
future与async的关系
std::future 是对潜在结果的一个句柄,std::async 是将函数包装为异步任务的入口。通过 fut.get(),调用方可以得到结果并自动处理异常;通过 fut.wait()、wait_for()/wait_until() 可以实现非阻塞等待策略。

下面的代码演示了基本的异步提交和阻塞获取:
#include <future>
#include <iostream>
#include <thread>
#include <chrono>int main() {auto f = std::async(std::launch::async, []() {std::this_thread::sleep_for(std::chrono::seconds(2));return 42;});// 同步等待结果int result = f.get();std::cout << "result=" << result << std::endl;return 0;
}
2. 使用std::future获取异步结果
std::future的基本用法
通过 std::async 提交任务后,会得到 std::future。调用 get() 会阻塞直到结果就绪,同时会把任务中的异常重新抛出给调用方。
你还可以使用 wait() 或 wait_for 来实现非阻塞检查,避免不必要的阻塞。这样可以组合事件驱动逻辑与传统阻塞点。
等待策略与超时
在某些场景中你需要一个超时机制,wait_for 和 wait_until 提供超时控制,帮助你在达到时间上限前决定是否继续等待或切换策略。
综合使用 条件判断、超时检测 与 结果提取,可以实现容错性更高的异步流程。
示例演示了 wait_for 的用法与 fut.get() 的组合:
#include <future>
#include <iostream>
#include <chrono>
#include <thread>int main() {std::future<int> f = std::async(std::launch::async, []() {std::this_thread::sleep_for(std::chrono::seconds(1));return 5;});if (f.wait_for(std::chrono::milliseconds(500)) == std::future_status::ready) {std::cout << "early: " << f.get() << std::endl;} else {std::cout << "still computing..." << std::endl;std::cout << "final: " << f.get() << std::endl;}return 0;
}
3. 使用std::async实现并发任务
std::async的两种执行策略
std::async 提供两种执行策略:std::launch::async 会把任务放到新的线程中并发执行,而 std::launch::deferred 会推迟执行,直到你调用 get() 或 wait()。
正确的策略选择关系到开销、响应性与资源管理。对于 CPU 密集型任务,通常优先使用 async,而对延迟敏感的工作可评估是否使用 deferred。
并发任务的组织与结果收集
当需要同时执行多组独立任务时,可以把它们封装为若干 std::future,再通过 get() 顺序收集结果。这样可以实现简单的并发模式而无需显式的线程管理。
#include <future>
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>int heavyWork(int x) {// 模拟重计算std::this_thread::sleep_for(std::chrono::milliseconds(200));return x * x;
}int main() {std::vector data = {1,2,3,4,5};std::vector> futures;for (auto v : data) {futures.emplace_back(std::async(std::launch::async, heavyWork, v));}std::cout << "tasks launched: " << futures.size() << std::endl;for (auto &f : futures) {std::cout << f.get() << " ";}std::cout << std::endl;return 0;
}
4. 异步错误处理与异常安全
异常传递与处理
在异步任务内部抛出的异常会被封装到 std::future,get() 会重新抛出该异常,确保异常沿异步边界传播。
为了确保安全性,调用方应将对 get() 的调用放在 try-catch 块内,以捕捉并处理异常情况。
#include <future>
#include <iostream>
#include <stdexcept>int main() {auto f = std::async(std::launch::async, []() {throw std::runtime_error("boom");return 1;});try {int x = f.get();} catch (const std::exception &e) {std::cout << "caught: " << e.what() << std::endl;}return 0;
}
5. 进阶技巧:高效调度与资源管理
任务分解与粒度控制
将大任务拆分成更小的异步子任务可以提升吞吐率,但粒度过小也会带来调度开销,需要通过 基准测试和 成本估算来找到平衡。
在设计阶段,优先明确可并行的独立单元,并使用 并发边界来避免数据竞争与锁开销。
与其他并发工具的整合
标准库的 std::thread、std::mutex 及其他相关工具可以与 std::future 配合使用,形成更丰富的并发模式。对于复杂场景,可以实现一个简单的线程池来复用线程,减少线程创建成本。
#include <vector>
#include <future>
#include <iostream>int work(int x) { return x * 3; }int main() {std::vector nums = {1,2,3,4,5};std::vector> futures;for (int n : nums) {futures.emplace_back(std::async(std::launch::async, work, n));}for (auto &f : futures) {std::cout << f.get() << " ";}std::cout << std::endl;
}


