C++11 线程共享状态
一、问题提出
首先,我们假设一种情况,在多线程中,出现这么一种情况:
两条线程:thread1 和 thread2
某种特殊环境中,thread2需要得到thread1中的某个值才能进行数据处理,那怎么做才能达到这种效果?
方法一:
在主线程中等待,直到thread1处理完后,按顺序处理thread2;
但是这种效率太低,导致主线程一直阻塞等待
方法二:
同时开启两个线程,thread1和thread2;在thread2中阻塞等待thread1处理好数据,并进行下一步操作
优点:
不需要更多的资源来等待thread1的完成
那具体怎么做呢?
还好C++11 为我们提供了相关的函数类:promise和future
二、promise和future
头文件:
#include <future>
promise 对象可以保存某一类型 T 的值,该值可被 future 对象读取(可能在另外一个线程中),因此 promise 也提供了一种线程同步的手段。在 promise 对象构造时可以和一个共享状态(通常是std::future)相关联,并可以在相关联的共享状态(std::future)上保存一个类型为 T 的值。
可以通过 get_future 来获取与该 promise 对象相关联的 future 对象,调用该函数之后,两个对象共享相同的共享状态(shared state)
- promise 对象是异步 Provider,它可以在某一时刻设置共享状态的值。
- future 对象可以异步返回共享状态的值,或者在必要的情况下阻塞调用者并等待共享状态标志变为 ready,然后才能获取共享状态的值。
主要涉及到这几个函数:
std::promise::get_future:返回一个与promise共享状态相关联的future对象
std::promise::set_value:设置共享状态的值,此后promise共享状态标识变为ready
std::promise::set_exception:为promise设置异常,此后promise的共享状态标识变为ready
std::promise::set_value_at_thread_exit:设置共享状态的值,但是不将共享状态的标志设置为 ready,当线程退出时该 promise 对象会自动设置为 ready(注意:该线程已设置promise的值,如果在线程结束之后有其他修改共享状态值的操作,会抛出future_error(promise_already_satisfied)异常)
std::promise::swap:交换 promise 的共享状态
std::future
简单来说,std::future提供了一种访问异步操作结果的机制。
通常一个异步操作我们是不能马上就获取操作结果的,只能在未来某个时候获取。我们可以以同步等待的方式来获取结果,可以通过查询future的状态(future_status)来获取异步操作的结果。future_status有三种状态:
deferred:异步操作还没开始
ready:异步操作已经完成
timeout:异步操作超时
获取future结果有三种方式:get、wait、wait_for,其中get等待异步操作结束并返回结果,wait只是等待异步操作完成,没有返回值,wait_for是超时等待返回结果。
注意:一个promise只能被获取到一次。
三、案例
#include <iostream>
#include <future>
#include <thread>
#include <exception>
using namespace std;
typedef struct PF
{
string name;
int age;
};
void get_int(promise<PF>&prom)
{
try
{
PF pf;
memset(&pf, 0, sizeof(pf));
pf.name = "test";
pf.age = 10;
//设置共享状态
prom.set_value(pf);
}
catch(exception)
{
prom.set_exception(current_exception());
}
}
void print_int(future<PF>&fut)
{
try
{
PF pf;
memset(&pf, 0, sizeof(pf));
////获取共享状态
pf = fut.get();
cout << "age:"<<pf.age << endl;
cout << "name:" << pf.name.c_str() << endl;
}
catch (exception& e)
{
cout << "exception:"<<e.what() << endl;
}
}
int main()
{
PF pf;
memset(&pf,0,sizeof(pf));
//生成对象
promise<PF>prom;
//与future关联
future<PF>fut = prom.get_future();
thread *t1 = new thread(get_int,ref(prom));
thread *t2 = new thread(print_int,ref(fut));
t1->join();
t2->join();
delete t1;
delete t2;
return 0;
}
想了解学习更多C++后台服务器方面的知识,请关注:
微信公众号:C++后台服务器开发