Promise 是C++标准库中用于异步编程的类模板,通常用于从完成一项任务的执行线程返回结果给启动该任务的线程。在这里,Promise对象充当了一个临时的标志,并将在一些时刻被一个结果值所取代。
一个Promise对象有两方面的对等关系:
- 一个Promise对象是为了保存某个特定的结果值分配的,这个结果值是在未来的某个时间点计算得到的。结果值可以是任意类型的值(void类型除外);也可以是指向常量和非常量(对象指针、函数或者成员函数)的指针;甚至是引用类型的“实值”。
- 一个Promise对象可以创建一个或多个std::future对象,用来承载该Promise对象所保存的结果值。只有当set_value()或者set_exception()被调用,这些结果值才能被执行。一旦被执行,这些结果值就可以通过std::future::get函数添加到std::future对象中。
一个使用Promise的生产者-消费者示例:
#include<future>
#include<iostream>
#include<thread>
void getData(std::promise<int>* prom_obj){
//do something to get the data
int data = 2;
std::this_thread::sleep_for(std::chrono::seconds(2));
prom_obj->set_value(data);
}
int main(){
std::promise<int> promise_obj;
std::future<int> future_obj = promise_obj.get_future();
std::thread t(getData, &promise_obj);
std::cout<<"Data received : "<<future_obj.get()<<std::endl;
t.join();
return 0;
}
在上述示例中,主线程创建了一个 promise 对象,并通过引用将其传递给新线程。新线程中执行一个获取数据的函数,该数据被存入 promise 对象中。
主线程通过调用从 promise 对象获取的 future 对象的get方法获取数据。需要注意的是,get方法是一个阻塞调用,它会一直等待,直到该数据可用。一旦数据可用,get就会返回数据。如果在设置数据值或异常之前销毁了 promise,get() 将抛出promise_broken 异常。
在异步编程中,可能会碰到这样的情况:比如创建了一个promise对象,然后在某个线程中通过get()访问它。然而,如果在调用get()之前,这个promise对象被析构(销毁),那个尝试获取结果的线程将会抛出std::future_error异常,其中error_code()将会返回std::future_errc::broken_promise。
一个显眼的处理方式就是确保promise对象的生命周期一直持续到已经调用set_value或者set_exception为止。除此之外,可以使用智能指针(例如std::shared_ptr)来管理promise对象的生命周期,确保promise对象在最后一个引用被释放时才被删除。
在捕获异常的时候,我们尽量做一些错误处理,使得程序还能使正常运行。例如:
std::promise<int> prom;
try {
// ...
prom.get_future().get();
}
catch (const std::future_error& e) {
if (e.code() == std::future_errc::broken_promise)
std::cout << "Caught broken_promise error\n";
else
std::cout << "Caught unexpected exception\n";
}
通过使用try-catch语句,当promise对象提前被析构时,我们可以捕获到这个异常,然后自行处理。