这三个是 C++11 引入的线程间通信、异步任务、获取线程返回值 的核心工具,解决了传统多线程无法直接获取返回值、无法安全传递异常、线程同步麻烦的问题。
我会用最通俗的语言 + 完整代码示例 + 核心原理,从基础到进阶讲透,保证你能彻底理解。
先搞懂核心定位:它们是干嘛的?
一句话总结三者关系:
std::async:启动一个异步任务(相当于自动创建线程 / 复用线程执行函数)std::future:未来的结果 (用来获取异步任务的返回值 / 异常)std::promise:承诺一个结果 (用来手动设置值 / 异常,再把结果交给 future)
简单比喻:
promise= 厨师,负责做好菜(设置值)future= 取餐号,负责取菜(获取值)async= 外卖平台,自动派厨师做菜,你只需要拿取餐号等结果
一、std::future:未来的结果(核心载体)
1. 是什么?
future 是一个模板类 ,用来等待异步操作的结果 。它本身不能直接存值 ,只能从 promise 或 async 那里获取结果。
2. 核心方法
| 方法 | 作用 |
|---|---|
get() |
阻塞等待,直到结果就绪,然后返回值(只能调用 1 次) |
wait() |
阻塞等待结果就绪,但不返回值 |
wait_for(timeout) |
等待指定时间,超时就返回,不卡死 |
wait_until(time) |
等待到指定时间点 |
valid() |
判断 future 是否还有效 |
3. 关键特性
get()只能调用一次,调用后 future 失效- 没结果时调用
get()会阻塞当前线程,直到结果到来 - 可以安全接收异步线程抛出的异常(传统线程做不到)
二、std::promise:手动承诺一个结果
1. 是什么?
promise 也是模板类,作用是:手动在某个线程中设置一个值 / 异常 ,然后把结果交给关联的 future,让另一个线程获取。
它是手动线程通信的工具。
2. 核心方法
| 方法 | 作用 |
|---|---|
get_future() |
获取和当前 promise 绑定的 future |
set_value(val) |
设置结果值(只能调 1 次) |
set_exception(e) |
设置异常(线程间传递异常) |
3. 完整示例:线程 A 给线程 B 传值
#include <iostream>
#include <thread>
#include <future>
using namespace std;
// 子线程函数:接收 promise,负责设置值
void worker(promise<int>& p) {
cout << "子线程:正在计算...\n";
this_thread::sleep_for(chrono::seconds(2)); // 模拟耗时
// ✅ 设置结果,交给 future
p.set_value(1024);
cout << "子线程:已设置结果 1024\n";
}
int main() {
// 1. 创建 promise(承诺返回 int)
promise<int> p;
// 2. 获取绑定的 future
future<int> f = p.get_future();
// 3. 启动子线程,把 promise 传进去
thread t(worker, ref(p));
cout << "主线程:等待子线程结果...\n";
// 4. 阻塞等待,获取结果
int res = f.get();
cout << "主线程:获取到结果 = " << res << endl;
t.join();
return 0;
}
4. 进阶:线程间传递异常
promise 最大的优势之一:子线程的异常可以抛给主线程,传统线程做不到!
void worker(promise<int>& p) {
try {
throw runtime_error("子线程出错啦!");
} catch (...) {
// ✅ 把异常设置给 promise
p.set_exception(current_exception());
}
}
int main() {
promise<int> p;
future<int> f = p.get_future();
thread t(worker, ref(p));
try {
f.get(); // 主线程 get() 时会收到异常
} catch (exception& e) {
cout << "主线程捕获异常:" << e.what() << endl;
}
t.join();
return 0;
}
三、std::async:最简单的异步任务(最常用)
1. 是什么?
async 是一个函数模板 ,自动创建 / 复用线程 执行函数,直接返回 future,不用手动管线程、promise。
它是日常开发最推荐的异步方式。
2. 两种启动策略(必懂)
| 策略 | 含义 | |
|---|---|---|
launch::async |
立即创建新线程执行任务(强制异步) | |
launch::deferred |
延迟执行 ,直到调用 get()/wait() 才在当前线程执行(同步) |
|
| 默认 | `async | deferred`,系统自动选择 |
3. 完整示例:获取异步函数返回值
#include <iostream>
#include <future>
using namespace std;
// 异步执行的函数
int calc(int x, int y) {
cout << "异步任务:计算中...\n";
this_thread::sleep_for(chrono::seconds(2));
return x + y;
}
int main() {
// ✅ 启动异步任务,立即创建线程执行 calc(10,20)
future<int> f = async(launch::async, calc, 10, 20);
cout << "主线程:做自己的事...\n";
// 阻塞等待结果
int res = f.get();
cout << "异步结果:" << res << endl;
return 0;
}
4. 优势
- 不用写
thread、不用写promise - 直接获取函数返回值
- 直接捕获函数异常
- 代码极简、安全
四、三者关系与底层原理(彻底吃透)
1. 数据通道:共享状态
三者底层都依赖一个叫 ** 共享状态(shared state)** 的堆内存:
promise→ 写共享状态future→ 读共享状态async→ 内部封装了promise,自动写结果
2. 完整关系图
异步任务/线程 → std::promise(set_value)→ 共享状态 → std::future(get)→ 主线程
std::async(自动执行)→ 内部 promise → 共享状态 → std::future → 主线程
3. 核心区别
| 工具 | 用途 | 手动 / 自动 |
|---|---|---|
future |
获取结果 | 被动读取 |
promise |
手动设置结果 | 手动线程通信 |
async |
启动异步任务 | 自动创建线程 + 自动返回 future |
五、高频坑点(一定要避)
-
future::get()只能调用一次第二次调用会直接崩溃,因为结果已经被取走了。 -
async如果不接收返回值,会同步阻塞错误写法:async(launch::async, calc); // 临时 future 立即析构,阻塞主线程正确写法:必须用
future接收。 -
deferred策略不会创建线程 它是延迟同步执行,不是异步,别用错。 -
promise和future是一一绑定的 一个promise只能绑定一个future,不能复用。 -
线程间传递异常必须用
set_exception子线程直接 throw,主线程收不到,必须通过promise传递。
六、完整综合示例(覆盖所有知识点)
#include <iostream>
#include <future>
using namespace std;
// 异步函数
int task(int a) {
this_thread::sleep_for(chrono::seconds(1));
if (a < 0) throw invalid_argument("参数不能为负");
return a * 10;
}
int main() {
// ========== 1. async 异步任务 ==========
future<int> f1 = async(launch::async, task, 10);
cout << "async 结果:" << f1.get() << endl;
// ========== 2. promise + future 手动通信 ==========
promise<int> p;
future<int> f2 = p.get_future();
thread t([&]() {
try {
p.set_value(task(20));
} catch (...) {
p.set_exception(current_exception());
}
});
try {
cout << "promise 结果:" << f2.get() << endl;
} catch (exception& e) {
cout << "捕获异常:" << e.what() << endl;
}
t.join();
return 0;
}
总结
std::future:获取异步结果 ,get()阻塞取值,只能取一次std::promise:手动设置结果 / 异常,用于手动线程通信std::async:自动启动异步任务,直接返回 future,最简单常用- 底层靠共享状态 通信,支持线程间安全传值 + 传异常
- 日常开发优先用
async,需要手动控制线程用promise+future
std::future:获取异步结果,获取promise提前手动设置好的值或者async异步执行任务返回的结果