當某個線程持有這把鎖的時候(就是所謂的加鎖),那麼這個線程是獨佔全部的資源,這裏的資源指的是執行的權限,其餘要搶奪資源的線程都不得不等待。在不少狀況下,這都容易適用,可是有些狀況下,卻會產生一些異常狀況。ios
在生產消費者模型當中,確定都會用到互斥鎖的機制的,當生產者往隊列中放數據的瞬間,消費者是不能取數據的,那這時候可能會遇見一個問題,若是生成者由於某些緣由,放數據過慢,可是消費者取數據很快,當隊列中沒有數據了,消費者還去取的話,就會發生異常狀況。有些人可能會說,加個條件判斷一下隊列是否爲空不就能夠了。編程
這個確定是固然能夠的,可是在隊列依舊沒有數據的這一段時間,是要不斷的循環判斷這個條件,CPU確定是會飆升的,浪費了不少沒必要要的資源。多線程
這時候咱們設想,可否設計這樣的一種機制,若是在隊列沒有數據的時候,消費者線程能一直阻塞在那裏,等待着別人給它喚醒,在生產者往隊列中放入數據的時候通知一下這個等待線程,喚醒它,告訴它能夠來取數據了。框架
因而多線程中的條件變量就橫空出世!函數
條件變量是多線程數據同步的一種操做,無論是用哪一種框架,哪一種語言實現多線程的功能,條件變量都是不得不考慮的一種狀況。C++中提供了#include <condition_variable>頭文件,裏面就包含了條件變量的相關類。其中有兩個很是重要的接口,wait()和notify_one(),wait()可讓線程陷入休眠狀態,意思就是不幹活了,notify_one()就是喚醒真正休眠狀態的線程,開始幹活了。固然還有notify_all()這個接口,顧名思義,就是通知全部正在等待的線程,起來幹活了。優化
如下是代碼的實現部分this
#include <iostream> #include <deque> #include <thread> #include <mutex> #include <condition_variable> using namespace std; deque<int> q; mutex mt; condition_variable cond; void thread_producer() { int count = 10; while (count > 0) { unique_lock<mutex> unique(mt); q.push_front(count); unique.unlock(); cout << "producer a value: " << count << endl; cond.notify_one(); this_thread::sleep_for(chrono::seconds(1)); count--; } } void thread_consumer() { int data = 0; while (data != 1) { unique_lock<mutex> unique(mt); while (q.empty()) cond.wait(unique); data = q.back(); q.pop_back(); cout << "consumer a value: " << data << endl; unique.unlock(); } } int main() { thread t1(thread_consumer); thread t2(thread_producer); t1.join(); t2.join(); return 0; }
生產者:首先生產者利用unique_lock來加鎖,而後將生產的數據放入隊列,打印,解鎖,一旦解鎖以後,消費者得到了執行機會。spa
消費者:另外一方面消費者就會經過unique_lock得到控制權,也就是得到鎖,而後判斷隊列爲空的話就一直盜用wait()函數阻塞在那裏,等待其餘線程來喚醒它。而阻塞該線程時,該函數會自動解鎖,容許其餘線程執行。線程
生產者:再次回到生產者這裏,生產者線程利用利用條件變量cond.notify_one()來通知阻塞的線程起來幹活了。設計
消費者:阻塞在那裏的消費者線程一旦獲得notify喚醒,該函數取消阻塞並獲取鎖,而後取出隊列中的數據,並打印,最後解鎖。
生產者:再次回到生產者,而後生產者休眠1秒,這裏休眠是爲了模擬生產者生產慢的狀況,實際開發的時候不要去休眠。最後減一,進入下一次生產。
以上就是利用條件變量來實現生產消費者模型,這個會大大下降CPU的佔有率,固然代價就是編程稍微有點麻煩,但與這優化程序來比,這確定是值的。
更多精彩內容,請關注同名公衆:一點筆記alittle