條件變量pthread_cond_signal、pthread_cond_wait

pthread_cond_signal函數的作用是發送一個信號給另外一個正在處於阻塞等待狀態的線程,使其脫離阻塞狀態,繼續執行.如果沒有線程處在阻塞等待狀態,pthread_cond_signal也會成功返回。
但使用pthread_cond_signal不會有“驚羣現象”產生,他最多隻給一個線程發信號。假如有多個線程正在阻塞等待着這個條件變量的話,那麼是根據各等待線程優先級的高低確定哪個線程接收到信號開始繼續執行。如果各線程優先級相同,則根據等待時間的長短來確定哪個線程獲得信號。但無論如何一個pthread_cond_signal調用最多發信一次。
另外,互斥量的作用一般是用於對某個資源進行互斥性的存取,很多時候是用來保證操作是一個原子性的操作,是不可中斷的。
用法:
pthread_cond_wait必須放在pthread_mutex_lock和pthread_mutex_unlock之間,因爲他要根據共享變量的狀態來決定是否要等待,而爲了不永遠等待下去所以必須要在lock/unlock隊中
共享變量的狀態改變必須遵守lock/unlock的規則
pthread_cond_signal即可以放在pthread_mutex_lock和pthread_mutex_unlock之間,也可以放在pthread_mutex_lock和pthread_mutex_unlock之後,但是各有各缺點。
之間:
pthread_mutex_lock
xxxxxxx
pthread_cond_signal
pthread_mutex_unlock
缺點:在某下線程的實現中,會造成等待線程從內核中喚醒(由於cond_signal)然後又回到內核空間(因爲cond_wait返回後會有原子加鎖的行爲),所以一來一回會有性能的問題。
在code review中,我會發現很多人喜歡在pthread_mutex_lock()和pthread_mutex_unlock(()之間調用 pthread_cond_signal或者pthread_cond_broadcast函數,從邏輯上來說,這種使用方法是完全正確的。但是在多線程環境中,這種使用方法可能是低效的。posix1標準說,pthread_cond_signal與pthread_cond_broadcast無需考慮調用線程是否是mutex的擁有者,也就是說,可以在lock與unlock以外的區域調用。如果我們對調用行爲不關心,那麼請在lock區域之外調用吧。這裏舉個例子:
       
我們假設系統中有線程1和線程2,他們都想獲取mutex後處理共享數據,再釋放mutex。請看這種序列:
       
1)線程1獲取mutex,在進行數據處理的時候,線程2也想獲取mutex,但是此時被線程1所佔用,線程2進入休眠,等待mutex被釋放。
       
2)線程1做完數據處理後,調用pthread_cond_signal()喚醒等待隊列中某個線程,在本例中也就是線程2。線程1在調用pthread_mutex_unlock()前,因爲系統調度的原因,線程2獲取使用CPU的權利,那麼它就想要開始處理數據,但是在開始處理之前,mutex必須被獲取,很遺憾,線程1正在使用mutex,所以線程2被迫再次進入休眠。
       
3)然後就是線程1執行pthread_mutex_unlock()後,線程2方能被再次喚醒。
       從這裏看,使用的效率是比較低的,如果再多線程環境中,這種情況頻繁發生的話,是一件比較痛苦的事情。
但是在LinuxThreads或者NPTL裏面,就不會有這個問題,因爲在Linux 線程中,有兩個隊列,分別是cond_wait隊列和mutex_lock隊列, cond_signal只是讓線程從cond_wait隊列移到mutex_lock隊列,而不用返回到用戶空間,不會有性能的損耗。
所以在Linux中推薦使用這種模式。
之後:
pthread_mutex_lock
xxxxxxx
pthread_mutex_unlock
pthread_cond_signal
優點:不會出現之前說的那個潛在的性能損耗,因爲在signal之前就已經釋放鎖了
缺點:如果unlock和signal之前,有個低優先級的線程正在mutex上等待的話,那麼這個低優先級的線程就會搶佔高優先級的線程(cond_wait的線程),而這在上面的放中間的模式下是不會出現的。
所以,在Linux下最好pthread_cond_signal放中間,但從編程規則上說,其他兩種都可以
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章