记录:学习多线程(七):condition_variable、wait、notify_one、notify_all、
条件变量std::condition_variable、wait()、notify_one()、
上述代码深入思考
notify_all()
#include<map>
#include<string>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
class A{
public:
//把收到的消息(玩家命令)入到一个队列的线程
void inMsgRecvQueue(){//unlock()
for(int i=0;i<100000; ++i){
std::unique_lock<std::mutex> sbguard1(my_mutex1);
cout<<"inMsgRecvQueue()执行,插入一个元素"<<i<<endl;
msgRecvQueue.push_back(i);/*假设这个数字i就是我们收到的*/
/*加入outMsgRecvQueue()正在处理一个事务,需要一段时间,而
不是正卡在wait()那里等你唤醒,那么此时notify_one()这个调用
没有效果*/
my_cond.notify_all();/*我们尝试把wait()唤醒,执行完这行,那么outMsgRecvQueue里边的wait()就会被唤醒;(只能通知一个线程)*/
}//end for
return;
}
bool outMsgLULproc(int &command){
/*双重锁定,双重检查*/
if(!msgRecvQueue.empty()){
std::unique_lock<std::mutex> sbguard1(my_mutex1);
if(!msgRecvQueue.empty()){
//消息队列不为空
command = msgRecvQueue.front();/*返回第一个元素
,但不检查元素是否存在*/
msgRecvQueue.pop_front();//移除第一个元素,但不返回;
return true;
}else{
//sleep(100);
cout<<"outMsmRecvQueue()执行,但目前消息队列为空"<<i<<endl;
}
}
return false;
}
//把数据从消息队列中取出的线程
void outMsgRecvQueue(){
int command = 0;
whlie(true){
std::unique_lock<std::mutex> sbguard1(mu_mutex1);
/*wait()用来等一个东西*/
/*如果第二个参数返回true,那么wait()直接返回,如果第二个参数
的lambda表达式返回值是false,那么wait()将解锁互斥量,并堵塞
到本行,那堵塞到什么时候为止呢?堵塞到其他某个线程调用
notify_one()成员函数为止,如果wait()没有第二个参数,
my_cond.wait(sbguard1);那么就跟第二个参数lambda表
达式返回false效果一样,当其他线程用notify_one将本wait()
(原本是睡着/堵塞)的状态唤醒后,wait就开始恢复干活了,恢复
后wait干什么活?
a//wait不断的尝试获得互斥量锁,如果获取不到,
那么流程就卡在wait()这里等着获取,如果获取到了锁,那么wait就
继续执行
b//上锁(实际上,获取到了锁就等于上了锁。)
b.1//如果wait有第二个参数,就判断lanbda表达式,如果lambda
表达式为false,那么wait()又对互斥量解锁,然后又休眠这里等待
再次被notify_oen()唤醒
b.2//如果表达式为true,则wait()返回流程走下来,此时互斥锁
被锁着。
b.3//如果wait没有第二参数,则wait返回,流程走下去。*/
my_cond.wait(sbguard1,[this]{/*一个lambda表达式就是一个
调用对象*/
if(!msgRecvQueue.empty())
return true;
return false;
});
/*只要流程能走下来,这个互斥量一定是被锁着的,同时
msgRecvQueue至少有一条数据*/
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
cout<<"outMsgRecvQueue()执行,取出一个元素"<<command<<"threadid="<<std::this_thread::get_id()<<endl;
sbguard1.unlock();/*因为unique_lock的灵活性,我们可以随时
的解锁,以免锁住太长时间*/
//执行一些具体的动作
}//end while
}
private:
std::list<int> msgRecvQueue: //容器,专门用于代表玩家给咱们发送过来的命令
std::mutex my_mutex1;//创建一个互斥量,一个互斥量是一把锁
std::condition_variable mycond;//生成一个条件变量对象
};
int main(){
A myobja;
std::thread myOutMsgObj(&A::outMsgRecvQueue,&myobja);/*第二个参数
是引用,才能保证线程里用的是用一个对象*/
std::thread myOutMsgObj2(&A::outMsgRecvQueue,&myobja);
std:;thread myInMsgObj(&A::inMsgRecvQueue,&myobja);
myOutMsgObj.join();
myOutMsgObj2.join();
myInMsgObj.join();
return 0;
}
//条件变量std::condition_variable、wait()、notify_one()、
//线程A:等待一个条件满足
//线程B:专门往消息队列中扔消息(数据)
//std::condition_variable实际上是一个类,是一个和条件相关的一个类,说白了就是等待要给条件达成。
//这个类需要和互斥量来配合工作,用的时候我们要生成这个类的对象‘
//上述代码的深入思考
//notify_all()