C++标准库中的future和promise是异步编程的重要组件,二者配合可以实现线程间的结果传递和同步,不需要手动使用互斥锁和条件变量就能完成异步任务的结果获取。promise用于在一个线程中设置结果,future用于在另一个线程中获取这个结果,二者共享一个共享状态,结果设置后future就能感知到并获取对应值。

future和promise的基本概念
std::promise是一个模板类,用于在一个线程中存储一个值或者异常,这个值后续可以被关联的std::future对象获取。std::future同样是模板类,用于获取异步操作的结果,当结果还没有准备好时,调用future的get方法会阻塞当前线程,直到结果就绪。
二者的关联关系是通过std::promise::get_future方法建立的,调用这个方法会返回一个和当前promise关联的future对象,二者共享同一个共享状态,这个状态中存储了异步操作的结果或者异常信息。
基础使用示例
下面是一个最简单的使用示例,在主线程中创建promise,把关联的future传给子线程,子线程中通过promise设置结果,主线程通过future获取结果。
#include <iostream>
#include <future>
#include <thread>
// 子线程执行的函数,接收promise对象
void async_task(std::promise<int> prom) {
// 模拟异步操作耗时
std::this_thread::sleep_for(std::chrono::seconds(2));
// 设置promise的结果
prom.set_value(100);
}
int main() {
// 创建promise对象,存储int类型结果
std::promise<int> prom;
// 获取关联的future对象
std::future<int> fut = prom.get_future();
// 启动子线程,传入promise对象,注意要使用std::move转移所有权
std::thread t(async_task, std::move(prom));
// 主线程获取结果,此时会阻塞直到子线程设置结果
int result = fut.get();
std::cout << "异步任务结果: " << result << std::endl;
t.join();
return 0;
}
传递异常的场景
如果异步操作中出现异常,也可以通过promise传递异常,future获取结果时会重新抛出这个异常,方便调用方处理错误情况。
#include <iostream>
#include <future>
#include <thread>
#include <stdexcept>
void async_task_with_exception(std::promise<int> prom) {
try {
// 模拟操作出现异常
throw std::runtime_error("异步任务执行失败");
prom.set_value(200);
} catch (...) {
// 捕获异常并设置到promise中
prom.set_exception(std::current_exception());
}
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(async_task_with_exception, std::move(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的其他常用方法
除了get方法,future还有wait和wait_for方法,用于等待结果就绪或者检查结果的就绪状态。
wait():阻塞当前线程,直到结果就绪,没有返回值。wait_for(duration):阻塞当前线程一段时间,如果在指定时间内结果就绪,返回std::future_status::ready,否则返回std::future_status::timeout。wait_until(time_point):阻塞当前线程直到指定时间点,根据结果就绪情况返回对应的状态。
下面是一个使用wait_for的示例,避免无限阻塞:
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
void long_task(std::promise<int> prom) {
std::this_thread::sleep_for(std::chrono::seconds(3));
prom.set_value(300);
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(long_task, std::move(prom));
// 等待1秒,检查结果是否就绪
auto status = fut.wait_for(std::chrono::seconds(1));
if (status == std::future_status::ready) {
std::cout << "结果已就绪: " << fut.get() << std::endl;
} else if (status == std::future_status::timeout) {
std::cout << "等待超时,结果还未就绪" << std::endl;
// 继续等待或者做其他处理
fut.wait();
std::cout << "最终获取到结果: " << fut.get() << std::endl;
}
t.join();
return 0;
}
使用注意事项
- promise对象只能调用一次set_value或者set_exception,重复调用会导致未定义行为。
- promise对象不能被拷贝,只能被移动,所以在传递给线程的时候需要使用std::move转移所有权。
- 如果promise对象在被销毁前没有设置结果,关联的future调用get的时候会抛出std::future_error异常,错误码是std::future_errc::broken_promise。
- future的get方法只能调用一次,重复调用会导致未定义行为,如果需要多次获取结果,可以使用std::shared_future。
shared_future的使用场景
如果有多个线程需要获取同一个异步任务的结果,可以使用std::shared_future,它可以被多个线程同时访问,get方法可以被多次调用。
#include <iostream>
#include <future>
#include <thread>
#include <vector>
void async_task(std::promise<int> prom) {
std::this_thread::sleep_for(std::chrono::seconds(2));
prom.set_value(400);
}
void consumer_task(std::shared_future<int> fut, int id) {
int result = fut.get();
std::cout << "消费者" << id << "获取到结果: " << result << std::endl;
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
// 转换为shared_future
std::shared_future<int> shared_fut = fut.share();
std::thread t(async_task, std::move(prom));
// 启动多个消费者线程
std::vector<std::thread> consumers;
for (int i = 0; i < 3; i++) {
consumers.emplace_back(consumer_task, shared_fut, i);
}
t.join();
for (auto& c : consumers) {
c.join();
}
return 0;
}