條件變量是thread庫提供的一種用於等待的同步機制,可以實現線程間的通信,它必須與互斥量配合使用,等待另一個線程中某個事件的發生(滿足某個條件),然后線程才能繼續執行。
thread庫提供兩種條件變量對象condition_variable和condition_variable_any,一般情況下,我們應該使用condition_variable_any,它能夠適用更廣泛的互斥量類型。
用法:擁有條件變量的線程先鎖定互斥量,然后循環檢查某個條件,如果條件不滿足,那么就調用條件變量的成員函數wait()等待直至條件滿足。其他線程處理條件變量要求的條件,當條件滿足時調用它的成員函數notify_one()或notify_all(),以通知一個或者所有正在等待條件變量的線程停止等待繼續執行。
wait():當前線程調用wait()后將被阻塞,直到另外某個線程調用notify_*喚醒當前線程;當線程被阻塞時,該函數會自動調用std::mutex的unlock()釋放鎖,使得其它被阻塞在鎖競爭上的線程得以繼續執行。一旦當前線程獲得通知(notify,通常是另外某個線程調用notify_*喚醒了當前線程),wait()函數也是自動調用std::mutex的lock()。
生產者-消費者模式:
#include <boost/thread.hpp>
#include <boost/ref.hpp>
#include <iostream>
#include <stack>
boost::mutex io_mu;
class buffer
{
private:
boost::mutex mu; // 互斥量,配合條件變量使用
boost::condition_variable_any cond_put; // 寫條件變量
boost::condition_variable_any cond_get; // 讀條件變量
std::stack<int> stk; // 緩沖區對象
int un_read, capaccity;
bool is_full() // 緩沖區滿判斷
{
return un_read == capaccity;
}
bool is_empty() // 緩沖區空判斷
{
return stk.size() == 0;
}
public:
buffer(std::size_t n) :un_read(0), capaccity(n){}
void put(int x) // 寫數據
{
{ // 開始一個局部域
boost::mutex::scoped_lock lock(mu); // 鎖定互斥量
while (is_full()) // 檢查緩沖區是否滿
{
{ // 局部域,鎖定io_mu
boost::mutex::scoped_lock lock(io_mu);
std::cout << "full waiting..." << std::endl;
}
cond_put.wait(mu); // 條件變量等待
} // 條件滿足,停止等待
stk.push(x); // 壓棧,寫入數據
++un_read;
} // 通知前解鎖互斥量,條件變量的通知不需要互斥量鎖定
cond_get.notify_one(); // 通知可以讀數據
}
void get(int *x) // 讀數據
{
{ // 局部域開始
boost::mutex::scoped_lock lock(mu); // 鎖定互斥量
while (is_empty()) // 檢查緩沖區是否空
{
{ // 鎖定io_mu
boost::mutex::scoped_lock lock(io_mu);
std::cout << "empty waiting..." << std::endl;
}
cond_get.wait(mu); // 條件變量等待
} // 條件滿足,停止等待
--un_read;
*x = stk.top(); // 讀取數據
stk.pop();
} // 通知前解鎖
cond_put.notify_one();
}
};
buffer buf(5); // 定義一個緩沖區對象
void producer(int n) // 生產者
{
for (int i = 0; i < n; ++i)
{
{
boost::mutex::scoped_lock lock(io_mu);
std::cout << "put: " << i << std::endl;
}
buf.put(i); // 寫入數據
}
}
void consumer(int n) // 消費者
{
int x;
for (int i = 0; i < n; ++i)
{
{
buf.get(&x); // 讀取數據
boost::mutex::scoped_lock lock(io_mu);
std::cout << "get: " << x << std::endl;
}
}
}
int main()
{
boost::thread t1(producer, 20);
boost::thread t2(consumer, 10);
boost::thread t3(consumer, 10);
t1.join();
t2.join();
t3.join();
return 0;
}
運行截圖:


