C++11多線程(三)condition_variable、wait()、notify_one()

condition_variable

這是一個等待條件成立,然後喚醒線程的機制
wait() 等待被喚醒
notify_one()喚醒一個卡在wait處的線程
notify_all()喚醒所有卡在wait處的線程
有些線程的執行有條件限制,例如:只有在隊列中有元素的情況下才執行彈出和刪除元素的操作。
用法是先聲明一個condition_variable 的變量conv
在線程中使用 conv.wait( para1, para2 )
第一個參數是一個unique_guard對象
第二個參數是一個可調用對象(可以是一個lambda表達式),如下所示

unique_lock<mutex> guard(m_Mutex); //先鎖住
conv.wait(   guard,   [this] {return !m_Queue.empty();}   );

如果參數二返回的是true,程序繼續運行。
如果是false,則解鎖,然後卡住,指導被喚醒,再次鎖住互斥量,重新進行判斷
這個過程可以理解爲:
在這裏插入圖片描述
下面是一個對C++11多線程(二)中的代碼的改進

class A
{
	deque<int> m_Queue;
	mutex m_Mutex;
	std::condition_variable conv;
public:
	unique_lock<mutex> rtn_lock()
	{
		unique_lock<mutex> temp(m_Mutex);
		return temp;//返回局部對象,調用移動構造函數
	}
	void inMessage()
	{
		for (int i = 0; i < 100000; i++)
		{
			cout << "in  " << i << endl;
			unique_lock<mutex> guard = rtn_lock();
			m_Queue.push_back(i);
			conv.notify_one();//插入元素後就喚醒線程outMessage繼續執行
		}
	}
	void outMessage()
	{
		for (int i = 0; i < 100000; i++)
		{
			int command = -1;
			while (true)
			{
				unique_lock<mutex> guard1(m_Mutex);
				conv.wait(guard1, [this] {
					if (!m_Queue.empty())return true;//如果非空,就可以對m_Queue進行接下來的操作
					return false;//如果爲空,就解鎖,然後等着,直到被notify_one喚醒,再次鎖住互斥量,重新判斷
				});
				command = m_Queue.front();
				m_Queue.pop_front();
				guard1.unlock();
				cout << "out " << command << endl;
			}
		}
	}
};
int main()
{
	A a;
	thread tobjin(&A::inMessage, std::ref(a));
	thread tobjout(&A::outMessage, std::ref(a));
	tobjin.join();
	tobjout.join();
	
	system("pause");
	return 0;
}

注意:只有當一個線程卡在wait()的時候,另一個線程的notify_one纔有效
喚醒之後並不一定就會馬上執行,應爲喚醒之後還要加鎖,並不一定能成功加鎖,可能被另一個線程先鎖了。

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