在C++的并发编程体系中,future和promise是一对配合使用的异步通信组件,promise负责在异步任务中设置结果或异常,future则用于在后续逻辑中获取该结果,二者结合可以很方便地实现异步任务的回调与链式执行效果。

future与promise基础原理
future和promise的核心作用是实现异步任务间的状态与结果传递,二者的关系可以简单理解为:promise是结果的“生产者”,future是结果的“消费者”。
当我们在异步线程中执行任务时,可以创建一个promise对象,将其关联的future对象传递给需要获取结果的线程,异步任务完成后通过promise的set_value方法设置结果,后续线程就可以通过future的get方法阻塞等待并获取该结果。
基础使用示例
下面是一个最简单的future与promise配合的示例,演示异步任务计算结果的传递:
#include <iostream>
#include <future>
#include <thread>
// 异步任务函数,接收promise对象引用
void async_task(std::promise<int>& prom) {
// 模拟异步任务执行耗时
std::this_thread::sleep_for(std::chrono::seconds(1));
int result = 10 + 20;
// 设置promise的结果
prom.set_value(result);
}
int main() {
// 创建promise对象
std::promise<int> prom;
// 获取关联的future对象
std::future<int> fut = prom.get_future();
// 启动异步线程执行任务,传递promise引用
std::thread t(async_task, std::ref(prom));
// 在主线程中获取异步任务的结果,会阻塞直到结果就绪
int value = fut.get();
std::cout << "异步任务结果: " << value << std::endl;
t.join();
return 0;
}
基于future与promise实现异步回调
异步回调的核心逻辑是:当一个异步任务完成后,自动触发下一个处理逻辑。我们可以通过封装future和promise,在任务完成时执行预设的回调函数来达成这个效果。
回调实现思路
- 封装一个异步任务类,内部持有promise和future对象
- 提供设置回调函数的方法,回调函数在任务结果就绪后执行
- 异步任务执行完成后设置promise结果,同时触发回调函数
回调源码实现
下面是完整的异步回调实现代码:
#include <iostream>
#include <future>
#include <thread>
#include <functional>
#include <memory>
// 异步任务模板类,支持任意返回类型
template <typename T>
class AsyncTask {
public:
using Callback = std::function<void(const T&)>;
AsyncTask() : promise_(std::make_shared<std::promise<T>>()) {
future_ = promise_->get_future();
}
// 设置回调函数
void set_callback(Callback cb) {
callback_ = cb;
}
// 执行异步任务,func是任务逻辑
void execute(std::function<T()> func) {
// 启动异步线程执行任务
std::thread([this, func]() {
try {
// 执行任务逻辑获取结果
T result = func();
// 设置promise结果
promise_->set_value(result);
// 结果设置完成后触发回调
if (callback_) {
callback_(result);
}
} catch (...) {
// 捕获异常并设置到promise
promise_->set_exception(std::current_exception());
}
}).detach();
}
// 阻塞获取任务结果
T get() {
return future_.get();
}
private:
std::shared_ptr<std::promise<T>> promise_;
std::future<T> future_;
Callback callback_;
};
// 示例任务函数
int calculate() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return 100;
}
int main() {
// 创建int类型的异步任务
AsyncTask<int> task;
// 设置回调函数
task.set_callback([](const int& result) {
std::cout << "回调函数触发,结果: " << result << std::endl;
});
// 执行异步任务
task.execute(calculate);
// 主线程也可以获取结果
int result = task.get();
std::cout << "主线程获取结果: " << result << std::endl;
return 0;
}
实现异步任务的链式执行
链式执行指的是多个异步任务按顺序执行,前一个任务的结果作为后一个任务的输入,类似JavaScript中的Promise链式调用。我们可以通过封装future,让其在获取结果后可以继续绑定下一个异步任务来实现这个效果。
链式执行实现思路
- 封装一个
ChainFuture类,内部持有原始future对象 - 提供
then方法,接收一个处理函数,该函数接收前一个任务的结果,返回一个新的结果 then方法内部启动新的异步任务,等待前一个任务结果就绪后执行处理函数,返回新的ChainFuture对象
链式执行源码实现
下面是完整的链式执行实现代码:
#include <iostream>
#include <future>
#include <thread>
#include <functional>
#include <memory>
#include <type_traits>
// 链式Future模板类
template <typename T>
class ChainFuture {
public:
ChainFuture(std::future<T>&& fut) : future_(std::move(fut)) {}
// then方法,接收处理函数,返回新的ChainFuture
template <typename Func>
auto then(Func func) -> ChainFuture<decltype(func(std::declval<T>()))> {
using ResultType = decltype(func(std::declval<T>()));
// 创建promise用于传递下一个任务的结果
auto promise_ptr = std::make_shared<std::promise<ResultType>>();
std::future<ResultType> next_future = promise_ptr->get_future();
// 启动线程等待当前任务完成,执行then中的处理逻辑
std::thread([this, func, promise_ptr]() mutable {
try {
// 获取当前任务的结果
T prev_result = future_.get();
// 执行处理函数得到新结果
ResultType new_result = func(prev_result);
// 设置下一个任务的结果
promise_ptr->set_value(new_result);
} catch (...) {
promise_ptr->set_exception(std::current_exception());
}
}).detach();
return ChainFuture<ResultType>(std::move(next_future));
}
// 获取最终结果
T get() {
return future_.get();
}
private:
std::future<T> future_;
};
// 创建异步任务的辅助函数
template <typename Func>
auto async_task(Func func) -> ChainFuture<decltype(func())> {
using ResultType = decltype(func());
auto promise_ptr = std::make_shared<std::promise<ResultType>>();
std::future<ResultType> fut = promise_ptr->get_future();
std::thread([func, promise_ptr]() {
try {
ResultType result = func();
promise_ptr->set_value(result);
} catch (...) {
promise_ptr->set_exception(std::current_exception());
}
}).detach();
return ChainFuture<ResultType>(std::move(fut));
}
int main() {
// 链式执行异步任务
auto result = async_task([]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "第一个任务执行完成" << std::endl;
return 10;
}).then([](int value) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "第二个任务执行完成,输入值: " << value << std::endl;
return value * 2;
}).then([](int value) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "第三个任务执行完成,输入值: " << value << std::endl;
return value + 5;
}).get();
std::cout << "链式执行最终结果: " << result << std::endl;
return 0;
}
注意事项
- 使用promise设置结果时,必须保证每个promise只设置一次结果,重复设置会抛出
std::future_error异常 - 如果异步任务中可能抛出异常,需要通过
set_exception方法将异常设置到promise中,否则future的get方法会直接终止程序 - 链式执行中每个
then方法都会启动新的异步线程,如果任务过多需要考虑线程资源的管理,避免线程数量爆炸 - future的
get方法只能调用一次,多次调用会导致未定义行为,使用时需要注意结果获取的次数
通过上述实现,我们可以基于C++标准库的future和promise组件,灵活地实现异步任务的回调与链式执行,满足不同场景下的异步编程需求。