std::condition_variable

三個要素:條件,條件變量,互斥鎖。
條件:通常就是定義的一些變量,比如is_start, is_stop這些,和臨界區(qū)域是綁定的。
條件變量:std::condition_variable condition;? 用來阻塞線程和喚醒線程。
互斥鎖:std::mutex mutex;??條件變量需要和一個互斥鎖綁定,這個互斥鎖的作用為:a. 互斥地訪問臨界資源。 b. 保護(hù)條件。保護(hù)臨界資源互斥訪問就是保護(hù)條件互斥訪問,兩者綁定的。
多線程訪問一個共享資源(或稱臨界區(qū)),不僅需要用互斥鎖實(shí)現(xiàn)獨(dú)享訪問避免并發(fā)錯誤,在獲得互斥鎖進(jìn)入臨界區(qū)后,有時還需檢查特定條件是否成立。當(dāng)某個線程修改測試條件后,將通知其它正在等待條件的線程繼續(xù)往下執(zhí)行。PV操作的一個代碼實(shí)現(xiàn):
wait線程從條件不滿足,等待到重新執(zhí)行過程:

(wait前必須先加鎖)調(diào)用線程將自己放入等待隊(duì)列,mutex解鎖。(調(diào)用線程己加入等待隊(duì)列并解鎖,此時,允許其他線程改變“測試條件”)
掛起,等待pthread_cond_signal或pthread_cond_broadcast去喚醒。(其他線程改變測試條件,當(dāng)條件滿足時會發(fā)出通知)
被喚醒,mutex加鎖。
為什么在wait之前需要加鎖?
關(guān)閉了從檢測“測試條件”的時刻到將線程放入到等待隊(duì)列之間的這段“時間窗口”,使“測試條件”在線程加入等待隊(duì)列之前不會被其他線程修改,確保調(diào)用線程不會錯過“測試條件”的改變。
為什么使用while(1)語句來循環(huán)判斷“測試條件”?
線程API存在一個事實(shí)(很多語言中都如此,不僅僅是C++),就是即使在沒有通知條件變量的情況下線程也可能被喚醒,這樣的喚醒稱為虛假喚醒(spurious wakeups),但此時“測試條件”往往并沒有被滿足。因此正確的做法是,通過while循環(huán)確認(rèn)等待的“測試條件”是否確己發(fā)生并將其作為喚醒后的首個動作來處理,一旦確認(rèn)是“虛假喚醒”則繼續(xù)wait等待。而如果僅使用if語句,則喚醒后無法進(jìn)行這種確認(rèn)從而可能導(dǎo)致錯誤。
pthread_cond_signal 和 pthread_mutex_unlock順序問題
pthread_cond_signal放于pthread_mutex_unlock之前:wait線程被喚醒后是會對mutex重新加鎖的,但此時鎖可能還沒有被notify線程釋放(會發(fā)生這種現(xiàn)象就是因?yàn)橄到y(tǒng)對線程的調(diào)度),會造成等待線程從內(nèi)核中喚醒然后又回到內(nèi)核空間(因?yàn)閏ond_wait返回后會有原子加鎖的行為),所以一來一回會有性能的問題。但在Linux中推薦這種模式。
pthread_cond_signal放于pthread_mutex_unlock之后:不會出現(xiàn)之前說的那個潛在的性能損耗,因?yàn)樵趕ignal之前就已經(jīng)釋放鎖了。但如果unlock和signal之前,有個低優(yōu)先級的線程正在mutex上等待的話,那么這個低優(yōu)先級的線程就會搶占高優(yōu)先級的線程(cond_wait的線程)。