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纔有效
喚醒之後並不一定就會馬上執行,應爲喚醒之後還要加鎖,並不一定能成功加鎖,可能被另一個線程先鎖了。