promise用于在多个线程间传值,多用于一个线程执行到某个状态后,把自己的信息传递给另外一个线程(该线程在拿到这个信息前,会阻塞等待):
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
#include <functional>
using namespace std;
void init(promise<int> &p)
{
this_thread::sleep_for(chrono::seconds(1));
cout<<"init ok"<<endl;
p.set_value(1); //对promise赋值
this_thread::sleep_for(chrono::seconds(2));
cout<<"init done"<<endl;
}
int main ()
{
promise<int> pr1; //相当于一个对将来会被设置一个值的承诺
future<int> fu1 = pr1.get_future(); //每个promise对象都有一个对应的future对象,future对象用于管理未来的值
thread t1 (init, ref(pr1));
auto status = fu1.get(); //在promise赋值前一直阻塞,promise赋值后可以那到对应的值
cout<<"get init status:"<<status<<endl;
t1.join();
cout<<"t1 join"<<endl;
return 0;
}
运行程序输出:
init ok
get init status:1
init done
t1 join可以看到t1线程初始化到某个阶段时通过promise赋值,而主线程在promise被赋值前,会一直阻塞在future::get函数上。通过这种方式,可以很好的同步多线程直接的状态及数据。
当然也可以通过使用条件变量的方式达到同样的目的。
不过由于promise/future实际上是模板类,因此可以用于传递更为复杂的对象:
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
#include <functional>
using namespace std;
class A{
public:
A(int a):m_a(a)
{
cout<<"A Construct, this addr:"<<this<<endl;
}
A(const A& a):m_a(a.m_a)
{
cout<<"A Copy Construct, ori addr"<<&a<<" this addr:"<<this<<endl;
}
A(A&& a):m_a(a.m_a)
{
cout<<"A Move Construct, ori addr"<<&a<<" this addr:"<<this<<endl;
}
int m_a;
};
void init(promise<A> &p)
{
this_thread::sleep_for(chrono::seconds(1));
cout<<"init ok"<<endl;
p.set_value(A(5));
}
int main ()
{
promise<A> pr1;
future<A> fu1 = pr1.get_future();
thread t1 (init, ref(pr1));
auto status = fu1.get();
cout<<"get init status:"<<status.m_a<<endl;
t1.join();
cout<<"t1 join"<<endl;
return 0;
}
运行程序输出:
init ok
A Construct, this addr:0x292fccc
A Move Construct, ori addr0x292fccc this addr:0x756fa0
A Move Construct, ori addr0x756fa0 this addr:0x67fe0c
A Move Construct, ori addr0x67fe0c this addr:0x67fdb4
get init status:5 addr:0x67fdb4
t1 join
可见promise可以通过移动构造函数低成本的在线程间同步数据需要指出的是:
- promise允许move语义(右值构造,右值赋值),不允许拷贝(拷贝构造、赋值),future亦然。
- 与promise关联的future只能通过promise::get_future获取,一个promise实例只能与一个future关联共享状态,当在同一个promise上反复调用get_future会抛出future_error异常。
- set_value只能被调用一次,多次调用会抛出std::future_error异常。
- 如果promise直到销毁时,都未设置过任何值,则promise会在析构时自动设置为std::future_error,这会造成future.get抛出std::future_error异常。
- 通过promise::set_exception函数可以设置自定义异常,该异常最终会被传递到future,并在其get函数中被抛出。
既然promise可以用于传递对象,那么是否可以传递函数对象呢?
#include <iostream>
#include <thread>
#include <future>
#include <functional>
using namespace std;
int add(int a, int b, int &res)
{
return res=(a+b);
}
int sub(int a, int b, int &res)
{
return res=(a-b);
}
using T_FUNC = function<int(int, int, int&)>;
template<class TF>
void getFunc(promise<TF> &p, int funcType) //根据不同的funcType返回不同的函数
{
if(funcType == 1)
{
p.set_value(add); //与sub的写法都可以
}
else if(funcType == 2)
{
p.set_value(bind(sub, placeholders::_1, placeholders::_2, placeholders::_3));
}
}
template<class T, class ...Args>
void getRes(future<T> &fu, Args&& ...args) //完美转发
{
auto func = fu.get(); //获得函数对象
func(forward<Args>(args)...); //可变参数的完美转发
}
int main ()
{
int resAdd = 0, resSub = 0;
promise<T_FUNC> pr1;
future<T_FUNC> fu1 = pr1.get_future();
thread t1 (getFunc<T_FUNC>, ref(pr1), 1);
thread t2 (getRes<T_FUNC, int, int, int&>, ref(fu1), 1, 2, ref(resAdd));
promise<T_FUNC> pr2;
future<T_FUNC> fu2 = pr2.get_future();
thread t3 (getFunc<T_FUNC>, ref(pr2), 2);
thread t4 (getRes<T_FUNC, int, int, int&>, ref(fu2), 8, 6, ref(resSub));
t1.join();
t2.join();
cout<<"add(1,2)="<<resAdd<<endl;
t3.join();
t4.join();
cout<<"sub(8,7)="<<resSub<<endl;
return 0;
}
运行程序输出:
add(1,2)=3
sub(8,7)=2
版权声明:本文为jiemashizhen原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。