第八节 condition_variable、wait、notify_one、notify_all
一、条件变量condition_variable、wait、notify_one、notify_all
std::condition_variable实际上是一个类,是一个和条件相关的类,说白了就是等待一个条件达成。
1 2 3 4 5 6 7 8 9
| std::mutex mymutex1; std::unique_lock<std::mutex> sbguard1(mymutex1); std::condition_variable condition; condition.wait(sbguard1, [this] {if (!msgRecvQueue.empty()) return true; return false; }); condition.wait(sbguard1);
|
wait()用来等一个东西
如果第二个参数的lambda表达式返回值是false,那么wait()将解锁互斥量,并阻塞到本行
如果第二个参数的lambda表达式返回值是true,那么wait()直接返回并继续执行。
阻塞到什么时候为止呢?阻塞到其他某个线程调用notify_one()成员函数为止;
如果没有第二个参数,那么效果跟第二个参数lambda表达式返回false效果一样
wait()将解锁互斥量,并阻塞到本行,阻塞到其他某个线程调用notify_one()成员函数为止。
当其他线程用notify_one()将本线程wait()唤醒后,这个wait恢复后
1、wait()不断尝试获取互斥量锁,如果获取不到那么流程就卡在wait()这里等待获取,如果获取到了,那么wait()就继续执行,获取到了锁
2.1、如果wait有第二个参数就判断这个lambda表达式。
- a)如果表达式为false,那wait又对互斥量解锁,然后又休眠,等待再次被notify_one()唤醒
- b)如果lambda表达式为true,则wait返回,流程可以继续执行(此时互斥量已被锁住)。
2.2、如果wait没有第二个参数,则wait返回,流程走下去。
流程只要走到了wait()下面则互斥量一定被锁住了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <thread> #include <iostream> #include <list> #include <mutex> using namespace std; class A { public: void inMsgRecvQueue() { for (int i = 0; i < 100000; ++i) { cout << "inMsgRecvQueue插入一个元素" << i << endl; std::unique_lock<std::mutex> sbguard1(mymutex1); msgRecvQueue.push_back(i); condition.notify_one(); } } void outMsgRecvQueue() { int command = 0; while (true) { std::unique_lock<std::mutex> sbguard2(mymutex1); condition.wait(sbguard2, [this] { if (!msgRecvQueue.empty()) return true; return false;}); command = msgRecvQueue.front(); msgRecvQueue.pop_front(); sbguard2.unlock(); cout << "outMsgRecvQueue()执行,取出第一个元素" << endl; } } private: std::list<int> msgRecvQueue; std::mutex mymutex1; std::condition_variable condition; }; int main() { A myobja; std::thread myoutobj(&A::outMsgRecvQueue, &myobja); std::thread myinobj(&A::inMsgRecvQueue, &myobja); myinobj.join(); myoutobj.join(); }
|
二、深入思考
上面的代码可能导致出现一种情况:
因为outMsgRecvQueue()与inMsgRecvQueue()并不是一对一执行的,所以当程序循环执行很多次以后,可能在msgRecvQueue 中已经有了很多消息,但是,outMsgRecvQueue还是被唤醒一次只处理一条数据。这时可以考虑把outMsgRecvQueue多执行几次,或者对inMsgRecvQueue进行限流。
三、notify_all()
notify_one():通知一个线程的wait()
notify_all():通知所有线程的wait()