C++11多線程 條件變量condition_variable

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章