Linux執行緒同步 細說 互斥鎖 條件變數

2021-09-12 21:24:14 字數 2957 閱讀 1602

假設有多個執行緒共享的資源sum, 與之相關聯的mutex 是lock_s. 假設每個執行緒對sum的操作很簡單,與sum的狀態無關,比如只是sum++. 那麼只用mutex足夠了. 程式設計師只要確保每個執行緒操作前,取得lock,然後sum++,再unlock即可. 每個執行緒的對sum的操作**將像這樣:

add()

如果操作比較複雜,假設執行緒t0,t1,t2的操作是sum++,而執行緒t3則是在sum到達100的時候,列印出一條資訊,並對sum清零. 這種情況下,如果只用互斥鎖, 則t3需要乙個迴圈,每個迴圈裡先取得lock_s,然後檢查sum的狀態,如果sum>=100,則列印並清零,然後unlock.如果sum<100,則unlock,並sleep()本執行緒合適的一段時間。

這個時候,t0,t1,t2的**不變,t3的**如下

while (1)

else

}

這種辦法有兩個問題

1) sum在大多數情況下不會到達100,那麼對t3的**來說,大多數情況下,走的是else分支,只是lock和unlock,然後sleep().這浪費了cpu處理時間.

2) 為了節省cpu處理時間,t3會在探測到sum沒到達100的時候sleep()一段時間.這樣卻又帶來另外乙個問題,亦即t3響應速度下降.可能在sum到達200的時候,t4才會醒過來.

3) 這樣,程式設計師在設定sleep()時間的時候陷入兩難境地,設定得太短了節省不了資源,太長了又降低響應速度.真是難辦啊!

這個時候,condition variable從天而降,拯救了焦頭爛額的你.

首先定義乙個condition variable.

pthread_cond_t  cond_sum_ready = pthread_cond_initializer;

t0,t1,t2的**只要後面加兩行,像這樣

add()

而t3的**則是

while(1)

注意兩點:

1)在thread_cond_wait()之前,必須先lock相關聯的mutex。

pthread_cond_wait()實際上會先unlock該mutex(如果前面不加lock的話,這個unlock動作可能將別的執行緒的鎖給unlock掉,導致出錯(self)), 然後block,在目標條件滿足後再重新lock該mutex, 然後返回.

2)為什麼是while(sum<100),而不是if(sum<100) ?這是因為在pthread_cond_signal()和pthread_cond_wait()返回之間,有時間差,假設在這個時間差內,還有另外乙個執行緒t4又把sum減少到100以下了,那麼t3在pthread_cond_wait()返回之後,顯然應該再檢查一遍sum的大小.這就是用 while的用意.

另外,對於這裡提到的,引出另外乙個話題:

pthread_cond_signal即可以放在pthread_mutex_lock和pthread_mutex_unlock之間,也可以放在pthread_mutex_lock和pthread_mutex_unlock之後,各有有缺點。

a)放在之間:

pthread_mutex_lock

******x

pthread_cond_signal

pthread_mutex_unlock

缺點:在某些執行緒的實現中,會造成等待執行緒從核心中喚醒(由於cond_signal),然後又回到核心空間(因為cond_wait返回後會有原子加鎖的 行為)(意思是說這時候傳送signal的執行緒還沒有執行unlock,所以wait的執行緒進行lock會導致堵塞,並進入核心),所以一來一回會有效能的問題。

但是在linuxthreads或者nptl裡面,就不會有這個問題,因為在linux 執行緒中,有兩個佇列,分別是cond_wait佇列和mutex_lock佇列, cond_signal只是讓執行緒從cond_wait佇列移到mutex_lock佇列,而不用返回到使用者空間,不會有效能的損耗。所以在linux中推薦使用這種模式。

a)放在之後:

pthread_mutex_lock

******x

pthread_mutex_unlock

pthread_cond_signal

優點:不會出現之前說的那個潛在的效能損耗,因為在signal之前就已經釋放鎖了

缺點:如果unlock和signal之前,有個低優先順序的執行緒正在mutex上等待的話,那麼這個低優先順序的執行緒就會搶占高優先順序的執行緒(cond_wait的執行緒),而這在上面的放中間的模式下是不會出現的。所以最好還是用

while(sum<100)

pthread_cond_wait(&cond_sum_ready, &lock_s);

當喚醒之後,再檢查以下是否滿足條件。

訊號丟失問題現象(對於這種現象個人認為需要看具體的業務邏輯,來判斷是否有你有影響)

執行緒3處於下面的狀態:

在呼叫pthread_cond_wait()函式,但執行緒3還沒有進入wait cond的狀態的時候,  或者,正處在測試條件變數和呼叫pthread_cond_wait函式之間。 這時沒有執行緒正在處在阻塞等待的狀態下,此時執行緒1呼叫了 cond_singal, 這種情況下,執行緒1的這個cond_singal就丟失了。

ref:

my:

Linux 執行緒同步 互斥量(互斥鎖)

1 執行緒同步的目的是不管執行緒之間的執行如何穿插,其執行結果都是正確的。即保證多執行緒執行下結果的確定性。2 同步就是讓所有執行緒按照一定的規則執行,使得其正確性和效率都有跡可循,即執行緒同步就是對執行緒之間的穿插進行控制。3 每個物件都對應於乙個 互斥鎖 的標記,這個標記用來保證在任一時刻,只能...

Linux多執行緒同步 互斥鎖

當多個執行緒對同乙個資源進行訪問的時候,為了這個資源的安全性,我們需要對這個資源進行鎖定,規定同一時間只有乙個資源能夠獲得該鎖的鑰匙,其它執行緒要獲得該資源需要等待該執行緒 互斥鎖建立 pthread mutex t mutex 互斥鎖初始化 mutex pthread mutex initiali...

Linux 執行緒同步方法 互斥鎖

在單執行緒條件下,由於對資料操作,在同樣的時間下,只有乙個執行緒來操作。所以不用擔心資料的同步問題。現代的作業系統,大都提供併發機制,雖然有時候是表面的併發。在 linux 中,併發用的最多的是基於執行緒的併發,程序的代價太高了,這樣,乙個共享的資料,在同一時間內,可能有多個執行緒在操作。如果沒有同...