條件變量(Condition Variable)的通常用法是:線程 A 等待某個條件並掛起,直到線程 B 設置了這個條件,並通知條件變量,而後線程 A 被喚醒。經典的「生產者-消費者」問題就能夠用條件變量來解決。ios
這裏等待的線程能夠是多個,通知線程能夠選擇一次通知一個(notify_one
)或一次通知全部(notify_all
)。this
示例修改自:http://en.cppreference.com/w/...線程
首先是頭文件:code
#include <iostream> #include <string> #include <thread> #include <mutex> #include <condition_variable>
而後是兩個線程共享的全局變量:get
std::mutex mutex; std::condition_variable cv; std::string data; bool ready = false; // 條件 bool processed = false; // 條件
工做線程:string
void Worker() { std::unique_lock<std::mutex> lock(mutex); // 等待主線程發送數據。 cv.wait(lock, [] { return ready; }); // 等待後,繼續擁有鎖。 std::cout << "工做線程正在處理數據..." << std::endl; // 睡眠一秒以模擬數據處理。 std::this_thread::sleep_for(std::chrono::seconds(1)); data += " 已處理"; // 把數據發回主線程。 processed = true; std::cout << "工做線程通知數據已經處理完畢。" << std::endl; // 通知前,手動解鎖以防正在等待的線程被喚醒後又當即被阻塞。 lock.unlock(); cv.notify_one(); }
主線程:it
int main() { std::thread worker(Worker); // 把數據發送給工做線程。 { std::lock_guard<std::mutex> lock(mutex); std::cout << "主線程正在準備數據..." << std::endl; // 睡眠一秒以模擬數據準備。 std::this_thread::sleep_for(std::chrono::seconds(1)); data = "樣本數據"; ready = true; std::cout << "主線程通知數據已經準備完畢。" << std::endl; } cv.notify_one(); // 等待工做線程處理數據。 { std::unique_lock<std::mutex> lock(mutex); cv.wait(lock, [] { return processed; }); } std::cout << "回到主線程,數據 = " << data << std::endl; worker.join(); return 0; }
輸出:io
主線程正在準備數據... 主線程通知數據已經準備完畢。 工做線程正在處理數據... 工做線程通知數據已經處理完畢。 回到主線程,數據 = 樣本數據 已處理
下面是一些說明。class
與條件變量搭配使用的「鎖」,必須是 unique_lock
,不能用 lock_guard
。這個前面文章中已有說明。thread
等待前先加鎖。等待時,若是條件不知足,wait
會原子性地解鎖並把線程掛起。
條件變量被通知後,掛起的線程就被喚醒,可是喚醒也有多是假喚醒,或者是由於超時等異常狀況,因此被喚醒的線程仍要檢查條件是否知足,因此 wait
是放在條件循環裏面。cv.wait(lock, [] { return ready; });
至關於:while (!ready) { cv.wait(lock); }
。