1.條件變量std:: condition_variable、wait()、notify_one()
std:: condition_variable實際上是個類,是一個與條件相關的類,說白了就是等待一個條件的達成。這個類是需要和互斥量來配合工作的,用的時候我們要生成這個類的對象。
實例代碼:
線程A:等待一個條件滿足
線程B:專門往消息隊列扔消息(數據)
2.代碼深思考
視頻教程,老師講得很好!推薦開始視頻!
3.notify_all()
notify_one()只能通知一個線程;
notify_ all()通知所有線程,但是在本例中差異不大;
實例代碼如下:(解析在代碼註釋中)
#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++)
{
cout << "inMsgRecvQueue()執行,插入一個元素" << i << endl;
std::unique_lock<std::mutex> sbguard(my_mutex);
msgRecvQueue.push_back(i);
//假如outMsgRecvQueue()正在處理一個事務,需要一段時間,而不是正卡在wait()那裏等待你的喚醒,
//那麼此時這個notify_one()這個調用也許就沒效果;
my_cond.notify_one();//我們嘗試把wait()線程喚醒,執行完這行,那麼outMsgRecvQueue()裏面的wait()就會被喚醒
//喚醒之後的事情後續研究;
//my_cond.notify_all(); //通知所有線程
//...
//其他處理代碼
}
}
//把數據從消息隊列取出的線程
void outMsgRecvQueue()
{
int command = 0;
while (true)
{
std::unique_lock<std::mutex> sbguard(my_mutex);
//wait()用來等一個東西
//如果第二個參數lambda表達式返回值是true,那麼wait()直接返回;
//如果第二個參數lambda表達式返回值是false,那麼wait()將解鎖互斥量,並且堵塞到本行
//那堵到什麼時候爲止?堵塞到其他線程調用notify_one()成員函數爲止。
//如果wait()沒有第二個參數:my_cond.wait(sbguard);那麼就跟第二個參數返回false效果一樣,
//那麼wait()將解鎖互斥量,並且堵塞到本行,堵塞到其他線程調用notify_one()成員函數爲止。
//但其他線程用notify_one()將本wait(原來是睡着/堵塞)的狀態喚醒後,wait()就開始恢復幹活了,那恢復後的
//wait()幹什麼活?
//a)wait()不斷的嘗試重新獲取互斥量鎖,如果獲取不到,那麼流程就卡在wait()這裏等着獲取,如果獲取到了互斥鎖,
//那麼wait()就繼續執行b
//b)上鎖(實際上獲取鎖了就等於上了鎖)
//b.1)如果wait有第二個參數(lamdba),就判斷這個lamdba表達式,如果表達式爲false,
//那麼wait()又對互斥量解鎖然後又休眠,這裏繼續等待再次被notify_one()喚醒
//b.2)如果lamdba表達式爲true,則wait()返回,流程走下來(此時互斥鎖被鎖着)
//b.3)如果wait()沒有第二個參數,則wait()返回,流程走下來
//爲防止虛假喚醒:wait()中要有第二個參數(lambda)並且這個lambda中要正確處理公共數
// 據是否存在
my_cond.wait(sbguard, [this] { //一個lambda就是一個可調用對象(函數)
if (!msgRecvQueue.empty())
return true;
return false;
});
//流程能走到 這裏來,這個互斥鎖一定是鎖着的。同時msgRecvQueue至少有一條數據的
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
sbguard.unlock(); //因爲unique_lock的靈活性,所以我們可以隨時解鎖,以免鎖住太長時間
cout << "outMsgRecvQueue()執行,取出一個元素" << command << endl;
}//end while
}
private:
std::list<int> msgRecvQueue;//容器(消息隊列),代表玩家發送過來的命令。
std::mutex my_mutex;//創建一個互斥量(一把鎖)
std::condition_variable my_cond;//生成一個條件變量對象
};
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();
cout << "主線程執行!" << endl;
return 0;
}
注:該文是C++11併發多線程視頻教程筆記,詳情可學習:https://study.163.com/course/courseMain.htm?courseId=1006067356