1.条件变量condition_variable、wait()、notify_one()(通知一个线程)
1.1condition_variable实际上是一个类,是一个和条件相关的一个类,等待一个条件达成,这个类需要和互斥量来配合工作,用的时候我们要生成这个类的对象。
1.2.1wait()函数用于等待一个消息,他的第二个参数lambda表达式返回值是true,那wait()直接返回,否则wait()将解锁互斥量,并堵塞到本行,堵塞到其他某个线程调用notify_one()成员函数为止。如果wait()没有第二个参数,那么结果和lambda表达式返回false一样。
1.2.2当线程调用notify_one()唤醒wait()(原先堵塞状态)时,wait()恢复后,不断地尝试重新获取互斥量锁,如果获取不到,那么流程卡在wait这里等着获取,如果获取到了锁,那么就判断wait()是都有第二个参数,如果有,那么判断lambda表达式值的真假,如果为true,则wait返回,流程走下去(此时互斥锁被锁着),如果为false那么wait对互斥量解锁,继续睡眠堵塞状态。如果没有结果和true的结果是一致的。
注:notify_one的效果不一定能快速唤醒wait(),如果另外一个线程不是卡在wait处等待唤醒,在做其他事务是,唤醒是无效的。inMsgRecvQueue()与outMsgRecvQueue()调用的时候两个线程对锁的竞争,会出现inMsgRecvQueue()调用更多,导致插入的数据过多。通过lambda表达式判断取数据时是否有数据,可以避免虚假唤醒。
lambda表达式的使用参考https://www.cnblogs.com/DswCnblog/p/5629165.html
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 using namespace std;
8
9 class A{
10 public:
11 //把收到的消息入到一个队列的线程
12 void inMsgRecvQueue(){
13 for(int i = 0;i < 100000; ++i){
14 cout<<"inMsgRecvQueue(_)执行,插入一个元素"< sbguard1(my_mutex1);
16 msgRecvQueue.push_back(i);
17 my_cond.notify_one(); //通过调用该函数唤醒wait
18 }
19 return;
20 }
21
22 //把数据从消息队列中取出的进程
23 void outMsgRecvQueue(){
24 int command = 0;
25 while(true){
26 std::unique_lock sbguard1(my_mutex1);
27 my_cond.wait(sbguard1,[this]{
28 if(!msgRecvQueue.empty())
29 return true;
30 return false;
31 });
23 void outMsgRecvQueue(){
24 int command = 0;
25 while(true){
26 std::unique_lock sbguard1(my_mutex1);
27 my_cond.wait(sbguard1,[this]{
28 if(!msgRecvQueue.empty())
29 return true;
30 return false;
31 });
32 command = msgRecvQueue.front();
33 msgRecvQueue.pop_back();
34 sbguard1.unlock();
35 cout<<"outMsgRecvQueue()执行,取出一个元素";
36 }
37 }
38 private:
39 list msgRecvQueue;
40 mutex my_mutex1;
41 std::condition_variable my_cond; //生成一个条件变量对象
42 };
43 int main(){
44 A myobja;
45 thread myOutMsgobj(&A::outMsgRecvQueue,&myobja);
46 thread myInMsgobj(&A::inMsgRecvQueue,&myobja);
47 myInMsgobj.join();
48 myOutMsgobj.join();
49 return 0;
50 }
2.notify_all()(同时唤醒多个线程)
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 using namespace std;
8
9 class A{
10 public:
11 //把收到的消息入到一个队列的线程
12 void inMsgRecvQueue(){
13 for(int i = 0;i < 100000; ++i){
14 std::unique_lock sbguard1(my_mutex1);
15 cout<<"inMsgRecvQueue(_)执行,插入一个元素"< sbguard1(my_mutex1);
27 my_cond.wait(sbguard1,[this]{
28 if(!msgRecvQueue.empty())
29 return true;
30 return false;
31 });
32 command = msgRecvQueue.front();
33 msgRecvQueue.pop_back();
34 cout<<"outMsgRecvQueue()执行,取出一个元素"< msgRecvQueue;
40 mutex my_mutex1;
41 std::condition_variable my_cond; //生成一个条件变量对象
42 };
43 int main(){
44 A myobja;
45 thread myOutMsgobj(&A::outMsgRecvQueue,&myobja);
46 thread myOutMsgobj2(&A::outMsgRecvQueue,&myobja);
47 thread myInMsgobj(&A::inMsgRecvQueue,&myobja);
48 myInMsgobj.join();
49 myOutMsgobj.join();
50 myOutMsgobj2.join();
51 return 0;
52 }