std::async和std::future是C++11起支持的轻量级异步编程方式,用于启动可等待后台任务并获取返回值;它比手动管理线程更简洁,但不适用于需精细控制生命周期或频繁创建销毁的场景。

使用 std::async 和 std::future 是 C++11 起支持的轻量级异步编程方式,适合启动一个可等待的后台任务并获取返回值。它比直接管理线程更简洁,但不适用于需要精细控制生命周期或频繁创建/销毁的场景。
基本用法:启动异步任务并获取结果
std::async 启动一个异步任务,返回一个 std::future 对象;调用 get() 会阻塞直到结果就绪,并取回返回值(只能调用一次)。
示例:计算两个数的和,异步执行
#include#include #include #include int compute_sum(int a, int b) { std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作 return a + b; } int main() { // 启动异步任务(默认策略:系统决定是异步还是延迟执行) auto fut = std::async(compute_sum, 10, 20); std::cout << "主线程继续执行其他工作...\n"; // get() 阻塞等待结果(若尚未完成),并返回值 int result = fut.get(); // 此处可能阻塞约2秒 std::cout << "结果:" << result << "\n"; // 输出:30 return 0; }
显式指定启动策略:std::launch::async vs std::launch::deferred
默认行为(std::launch::async | std::launch::deferred)由实现决定。如需确定行为,应显式指定:
立即学习“C++免费学习笔记(深入)”;
-
std::launch::async:强制在新线程中立即执行 -
std::launch::deferred:延迟执行,直到调用get()或wait()时才在当前线程运行(类似惰性求值)
示例:强制异步执行
auto fut = std::async(std::launch::async, compute_sum, 5, 15); // 一定会新开线程,不会延迟
注意:std::launch::deferred 下,get() 不会创建线程,而是同步执行函数——这能避免线程开销,但也失去并发性。
处理异常:future 会传播异常
如果异步函数抛出异常,std::future::get() 会重新抛出该异常(封装为 std::exception_ptr)。务必捕获,否则程序终止。
int risky_task() {
throw std::runtime_error("Oops! Something went wrong.");
}
// ...
auto fut = std::async(risky_task);
try {
auto res = fut.get(); // 这里会抛出 runtime_error
} catch (const std::exception& e) {
std::cerr << "捕获异常:" << e.what() << "\n";
}
非阻塞检查与超时等待
用 wait_for() 或 wait_until() 可避免无限等待;valid() 和 wait_for(0s) 可轮询状态。
-
fut.wait_for(std::chrono::milliseconds(100)) == std::future_status::ready表示已就绪 -
fut.valid()返回false表示 future 已被移动或未绑定(如默认构造)
示例:带超时的等待
auto fut = std::async(std::launch::async, []{
std::this_thread::sleep_for(std::chrono::seconds(3));
return 42;
});
if (fut.wait_for(std::chrono::seconds(2)) == std::future_status::ready) {
std::cout << "及时完成:" << fut.get() << "\n";
} else {
std::cout << "超时,任务仍在运行\n";
}
基本上就这些。合理搭配 std::async 和 std::future 能快速写出清晰、安全的异步逻辑,但要注意资源释放时机(future 析构时若未取值且为 async 策略,会阻塞等待)、避免隐式拷贝(future 不可拷贝,只能移动),以及慎用默认启动策略。










