互斥鎖與條件變數

2021-09-27 03:05:18 字數 2918 閱讀 5878

pthread_cond_wait總和乙個互斥鎖結合使用。在呼叫pthread_cond_wait前要先獲取鎖。pthread_cond_wait函式執行時先自動釋放指定的鎖,然後等待條件變數的變化。在函式呼叫返回之前,自動將指定的互斥量重新鎖住。

int pthread_cond_signal(pthread_cond_t * cond);
pthread_cond_signal通過條件變數cond傳送訊息,若多個訊息在等待,它只喚醒乙個。pthread_cond_broadcast可以喚醒所有。呼叫pthread_cond_signal後要立刻釋放互斥鎖,因為pthread_cond_wait的最後一步是要將指定的互斥量重新鎖住,如果pthread_cond_signal之後沒有釋放互斥鎖,pthread_cond_wait仍然要阻塞。

激發條件有兩種形式,pthread_cond_signal()啟用乙個等待該條件的執行緒,存在多個等待執行緒時按入隊順序啟用其中乙個;而pthread_cond_broadcast()則啟用所有等待執行緒。

下面是另一處說明:給出了函式執行全過程。 為什麼在喚醒執行緒後要重新mutex加鎖?

了解 pthread_cond_wait() 的作用非常重要 – 它是 posix 執行緒訊號傳送系統的核心,也是最難以理解的部分。

鎖定互斥物件時,執行緒將呼叫 pthread_cond_wait(&mycond,&mymutex)。pthread_cond_wait() 呼叫相當複雜,因此我們每次只執行它的乙個操作。

pthread_cond_wait() 所做的第一件事就是同時對互斥物件解鎖(於是其它執行緒可以修改已鏈結列表),並等待條件 mycond 發生(這樣當 pthread_cond_wait() 接收到另乙個執行緒的「訊號」時,它將甦醒)。現在互斥物件已被解鎖,其它執行緒可以訪問和修改已鏈結列表,可能還會新增項。 【要求解鎖並阻塞是乙個原子操作】

此時,pthread_cond_wait() 呼叫還未返回。對互斥物件解鎖會立即發生,但等待條件 mycond 通常是乙個阻塞操作,這意味著執行緒將睡眠,在它甦醒之前不會消耗 cpu 週期。這正是我們期待發生的情況。執行緒將一直睡眠,直到特定條件發生,在這期間不會發生任何浪費 cpu 時間的繁忙查詢。從執行緒的角度來看,它只是在等待 pthread_cond_wait() 呼叫返回。

現在繼續說明,假設另乙個執行緒(稱作「2 號執行緒」)鎖定了 mymutex 並對已鏈結列表新增了一項。在對互斥物件解鎖之後,2 號執行緒會立即呼叫函式 pthread_cond_broadcast(&mycond)。此操作之後,2 號執行緒將使所有等待 mycond 條件變數的執行緒立即甦醒。這意味著第乙個執行緒(仍處於 pthread_cond_wait() 呼叫中)現在將甦醒。

現在,看一下第乙個執行緒發生了什麼。您可能會認為在 2 號執行緒呼叫 pthread_cond_broadcast(&mymutex) 之後,1 號執行緒的 pthread_cond_wait() 會立即返回。不是那樣!實際上,pthread_cond_wait() 將執行最後乙個操作:重新鎖定 mymutex。一旦 pthread_cond_wait() 鎖定了互斥物件,那麼它將返回並允許 1 號執行緒繼續執行。那時,它可以馬上檢查列表,檢視它所感興趣的更改。

來看乙個例子(你是否能理解呢?):

in thread1:

pthread_mutex_lock(&m_mutex);

pthread_cond_wait(&m_cond,&m_mutex);

pthread_mutex_unlock(&m_mutex);

in thread2:

pthread_mutex_lock(&m_mutex);

pthread_cond_signal(&m_cond);

pthread_mutex_unlock(&m_mutex);

為什麼要與pthread_mutex 一起使用呢? 這是為了應對 執行緒1在呼叫pthread_cond_wait()但執行緒1還沒有進入wait cond的狀態的時候,此時執行緒2呼叫了 cond_singal 的情況。 如果不用mutex鎖的話,這個cond_singal就丟失了。加了鎖的情況是,執行緒2必須等到 mutex 被釋放(也就是 pthread_cod_wait() 釋放鎖並進入wait_cond狀態 ,此時執行緒2上鎖) 的時候才能呼叫cond_singal.

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

之間:

pthread_mutex_lock

******x

pthread_cond_signal

pthread_mutex_unlock

缺點:在某下執行緒的實現中,會造成等待執行緒從核心中喚醒(由於cond_signal)然後又回到核心空間(因為cond_wait返回後會有原子加鎖的 行為),所以一來一回會有效能的問題。但是在linuxthreads或者nptl裡面,就不會有這個問題,因為在linux 執行緒中,有兩個佇列,分別是cond_wait佇列和mutex_lock佇列, cond_signal只是讓執行緒從cond_wait佇列移到mutex_lock佇列,而不用返回到使用者空間,不會有效能的損耗。

所以在linux中推薦使用這種模式。

之後:

pthread_mutex_lock

******x

pthread_mutex_unlock

pthread_cond_signal

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

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

互斥鎖與條件變數

最近複習湯小丹的 計算機作業系統 西安電子科技大學出版社,第三版 程序 執行緒同步章節時,發現乙個疑問。在講程序同步時,提到了兩類方法 訊號量機制和管程機制。訊號量機制又包括四種 整型訊號量 記錄型訊號量 and型訊號量 訊號量集。如果採用整型訊號量或記錄型訊號量,則在共享多個資源時,可能出現程序死...

互斥鎖與條件變數

互斥鎖用於保護臨界區,使得任何時刻只有乙個執行緒在執行其中的 確切的說,互斥鎖用於保護多個執行緒或多個程序分享的共享資料。posix互斥鎖被宣告為具有pthread mutex t資料型別的變數。若互斥鎖變數是靜態分配的,則初始化為 static pthread mutex t lock pthre...

互斥鎖與條件變數

條件改變這兩個操作之間存在乙個時間視窗。這裡存在著競爭。我們知道互斥量是可以用來解決上面的競爭問題的,所以條件變數本身 是由互斥量來保護的。既然判斷和睡眠是由互斥量來保護從而成為乙個原子操作,那麼其他改變條件的執行緒就應該以一致的方式修改條件 也就是說其他執行緒在改變條件狀態前也必須首先鎖住互斥量。...