在C++标准库的并发编程体系中,future和promise是用于线程间异步结果传递和同步的核心组件,二者通常配合使用,解决异步任务执行完成后结果回传的问题。

future和promise的核心定义
promise的作用
promise是结果的生产者,它可以在一个线程中设置某个值或者异常,这个设置的结果会被关联到对应的future上。我们可以将promise理解为一个承诺,承诺未来会给出某个结果,这个结果可以是普通数据,也可以是执行过程中抛出的异常。
future的作用
future是结果的消费者,它用来获取promise设置的结果。我们可以通过future的get()方法阻塞等待结果就绪,也可以通过wait()系列方法等待结果,还可以通过wait_for()等方法设置超时时间,避免无限阻塞。
future和promise的关联与分工
future和promise通过共享状态(shared state)关联在一起,一个promise对象和一个future对象共享同一个共享状态,二者的分工非常明确:
- promise负责在合适的时机向共享状态中写入结果或者异常
- future负责从共享状态中读取结果,当结果未就绪时,future的读取操作会阻塞当前线程直到结果就绪
需要注意的是,一个promise只能关联一个future,而一个future也只能对应一个promise,二者是一一对应的关系。
使用示例
下面通过一个完整的示例展示future和promise的配合使用方法,场景是主线程启动一个异步任务,异步任务计算两个数的和,将结果通过promise传递回主线程,主线程通过future获取结果。
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
// 异步任务函数,接收promise引用,计算完成后设置结果
void async_task(std::promise<int>& prom, int a, int b) {
// 模拟异步任务执行耗时
std::this_thread::sleep_for(std::chrono::seconds(2));
int result = a + b;
// 将计算结果设置到promise中,共享状态会变为就绪
prom.set_value(result);
}
int main() {
// 创建promise对象,模板参数为要传递的结果类型
std::promise<int> prom;
// 从promise获取关联的future对象
std::future<int> fut = prom.get_future();
// 启动线程执行异步任务,将promise通过引用传递给任务函数
std::thread t(async_task, std::ref(prom), 10, 20);
// 主线程可以做其他事情
std::cout << "主线程正在执行其他任务..." << std::endl;
// 通过future获取异步任务的结果,此时会阻塞直到结果就绪
int result = fut.get();
std::cout << "异步任务计算结果为:" << result << std::endl;
// 等待子线程执行完成
t.join();
return 0;
}
上述代码的执行流程为:
- 主线程创建
std::promise<int>对象,然后调用其get_future()方法得到关联的std::future<int>对象 - 主线程启动新线程执行
async_task函数,将promise的引用传递给该函数 - 新线程中模拟耗时计算后,调用
prom.set_value(result)将结果写入共享状态,此时共享状态变为就绪 - 主线程调用
fut.get()获取结果,若此时结果未就绪则会阻塞,直到新线程设置结果后返回结果值
异常传递示例
promise除了可以传递普通结果,还可以传递异步任务中抛出的异常,future获取结果时如果共享状态中存储的是异常,get()方法会重新抛出该异常,我们可以通过try-catch捕获。
#include <iostream>
#include <future>
#include <thread>
#include <stdexcept>
void task_with_exception(std::promise<int>& prom) {
try {
// 模拟任务中抛出异常
throw std::runtime_error("异步任务执行出错");
} catch (...) {
// 将捕获的异常设置到promise中
prom.set_exception(std::current_exception());
}
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(task_with_exception, std::ref(prom));
try {
int result = fut.get();
std::cout << "结果:" << result << std::endl;
} catch (const std::exception& e) {
std::cout << "捕获到异常:" << e.what() << std::endl;
}
t.join();
return 0;
}
适用场景总结
future和promise适合以下场景:
- 需要在一个线程中启动异步任务,并且在另一个线程中获取任务执行结果的场景
- 异步任务的结果产生时间不确定,需要阻塞等待或者设置超时等待的场景
- 需要跨线程传递异常,让调用方能够捕获异步任务中产生的异常的场景
需要注意的是,future的get()方法只能调用一次,多次调用会导致未定义行为,如果需要多次获取结果,可以使用shared_future。