一、有什么用:
當需要死循環判斷某個條件成立與否時【true or false】,我們往往需要開一個線程死循環來判斷,這樣非常消耗CPU。使用條件變量,可以讓當前線程wait,釋放CPU,如果條件改變時,我們再notify退出線程,再次進行判斷。
二、其他解釋
想要修改共享變量(即“條件”)的線程必須:
1. 獲得一個std::mutex
2. 當持有鎖的時候,執行修改動作
3. 對std::condition_variable執行notify_one或notify_all(當做notify動作時,不必持有鎖)
即使共享變量是原子性的,它也必須在mutex的保護下被修改,這是為了能夠將改動正確發布到正在等待的線程。
任意要等待std::condition_variable的線程必須:
1. 獲取std::unique_lock<std::mutex>,這個mutex正是用來保護共享變量(即“條件”)的
2. 執行wait, wait_for或者wait_until. 這些等待動作原子性地釋放mutex,並使得線程的執行暫停
3. 當獲得條件變量的通知,或者超時,或者一個虛假的喚醒,那么線程就會被喚醒,並且獲得mutex. 然后線程應該檢查條件是否成立,如果是虛假喚醒,就繼續等待。
【注: 所謂虛假喚醒,就是因為某種未知的罕見的原因,線程被從等待狀態喚醒了,但其實共享變量(即條件)並未變為true。因此此時應繼續等待】
https://en.cppreference.com/w/cpp/thread/condition_variable
三、代碼
std::deque<int> q;
std::mutex mu;
std::condition_variable cond;
void function_1() //生產者 { int count = 10; while (count > 0) { std::unique_lock<std::mutex> locker(mu); q.push_front(count); locker.unlock(); cond.notify_one(); // Notify one waiting thread, if there is one. std::this_thread::sleep_for(std::chrono::seconds(1)); count--; } } void function_2() //消費者 { int data = 0; while (data != 1) { std::unique_lock<std::mutex> locker(mu); while (q.empty()) cond.wait(locker); // Unlock mu and wait to be notified data = q.back(); q.pop_back(); locker.unlock(); std::cout << "t2 got a value from t1: " << data << std::endl; } } int main() { std::thread t1(function_1); std::thread t2(function_2); t1.join(); t2.join(); return 0; }
核心:
①、在消費者里判斷隊列是否為空后,如果不為空則wait,等待生產者發送notify信號
②、在生產者那里,如果生產了任務,則發送notify信號,告訴消費者可以試圖退出wait,判斷隊列是否為空,如果有任務則調度處理任務,如果還是空則說明此次notify是錯誤的,可能是其他地方發出來干擾的,生產者繼續wait。
③、流程:
軟件開啟,生成消費者線程消費隊列,應該是一個while循環,在循環里獲取鎖,再來一個while循環判斷條件,如果條件不成立則wait,wait會自動釋放鎖;
此時消費者已經沒有鎖了,在生產者線程里,獲取鎖,然后往里面加任務,退出作用域釋放鎖,然后notify告知消費者退出wait,消費者重新獲取鎖,然后從隊列里取任務;
整個過程,生產者加任務時生產者持有鎖,消費者取任務時消費者持有鎖。
對於此處補充:https://www.cnblogs.com/judes/p/11132918.html