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_wait()(或pthread_cond_timedwait(),下同)的競争條件(Race Condition)。mutex互斥鎖必須是普通鎖(PTHREAD_MUTEX_TIMED_NP)或者适應鎖 (PTHREAD_MUTEX_ADAPTIVE_NP),且在調用pthread_cond_wait()前必須由本線程加鎖 (pthread_mutex_lock()),而在更新條件等待隊列以前,mutex保持鎖定狀态,并線上程挂起進入等待前解鎖。在條件滿足進而離開 pthread_cond_wait()之前,mutex将被重新加鎖,以與進入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_cond_signal(&m_cond);