C++標準庫對條件變量有兩套實現:std::condition_variable和std::condition_variable_any,其中std::condition_variable_any的通用性更強,但是佔用系統資源更多。std::condition_variable需要搭配std::unique_lock使用。
首先介紹如何使用std::condition_variable:
案例1:條件變量condition_variable的使用
#include <mutex> //std::mutex std::lock_guard
#include <condition_variable> //std::condition_variable
std::mutex mut; //互斥量
std::queue<data_chunk> data_queue; //隊列
std::conditon_variable data_cond; //條件變量
void data_prparation_thread()
{
while(more_data_to_prepare())
{
data_chunk const data = prepare_data(); //獲取數據
std::lock_guard<std::mutex> lk(mut); //鎖管理器
data_queue.push(data); //數據寫隊列
data_cond.notify_one(); //通知等待線程
}
}
void data_processing_thread()
{
while(true)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, []{return !data_queue.empty();});//條件變量會首先判斷隊列是否爲空,若爲空則進行阻塞,等待通知。得到通知後,會再次判斷隊列是否爲空,若不爲空纔會獲取鎖纔會接觸阻塞,獲取鎖並進行後續程序。
data_chunk data = data_queue.front();
data_queue.pop();
lk.unlock();
process(data);
if (is_last_chunk(data))
break;
}
}
上述代碼有兩部分內容:一是數據準備線程,每次運行都會往隊列裏面添加元素並且通知數據處理線程;另一個是數據處理線程,在數據處理完之前一直循環運行,獲取數據-等待通知-獲取數據,按照這樣的規律進行。
案列2:
#include <mutex> //std::mutex std::lock_guard
#include <condition_variable> //std::condition_variable
bool ready = false;
std::mutex mut; //互斥量
std::conditon_variable data_cond; //條件變量
void process_thread1() //等待線程1
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, ready);
lk.unlock();
process1();
}
void process_thread2() //等待線程2
{
std::unique_lock<std::mutex> lk(mut);
data.cond.wait(lk, ready);
lk.unlock();
process2();
}
void data_init_thread() //通知線程
{
std::lock_guard<std::mutex> lk(mut);
ready = true;
data_cond.notify_all();
}
上述代碼中共有三個線程,等待線程1、等待線程2和等待線程3。等待線程1和等待線程2會阻塞,等待通知線程的通知纔會繼續運行。
案例三:有超時功能的條件變量
#include <mutex>
#include <condition_variable>
#include <chrono>
std::condition_variable cv;
bool done;
std::mutex m;
bool wait_loop()
{
auto const timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(500); //設置超時時間點
std::unique_lock<std::mutex> lk(m);
while(!done)
{
if(cv.wait_until(lk, timeout)==std::cv_status::timeout)//當超過某個時間點timeout時還無法獲得鎖,則會返回狀態值std::cv_status::timeout。還有一種std::condition_variable::wait_for(lk, duar)則是超過了時間段duar還無法獲得鎖就會返回狀態值
break;
}
return done;
}
條件變量實例cv會一直等待互斥量,直到超時