再談互斥鎖與條件變量!(終於搞清楚了啊!!!!!)

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仍然要阻塞。spa

 

不管哪一種等待方式,都必須和一個互斥鎖配合,以防止多個線程同時請求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);  it

 

In Thread2:io

pthread_mutex_lock(&m_mutex);   
pthread_cond_signal(&m_cond);   
pthread_mutex_unlock(&m_mutex);  ast

 

爲何要與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    xxxxxxxpthread_cond_signalpthread_mutex_unlock缺點:在某下線程的實現中,會形成等待線程從內核中喚醒(因爲cond_signal)而後又回到內核空間(由於cond_wait返回後會有原子加鎖的 行爲),因此一來一回會有性能的問題。可是在LinuxThreads或者NPTL裏面,就不會有這個問題,由於在Linux 線程中,有兩個隊列,分別是cond_wait隊列和mutex_lock隊列, cond_signal只是讓線程從cond_wait隊列移到mutex_lock隊列,而不用返回到用戶空間,不會有性能的損耗。因此在Linux中推薦使用這種模式。以後:pthread_mutex_lock    xxxxxxxpthread_mutex_unlockpthread_cond_signal優勢:不會出現以前說的那個潛在的性能損耗,由於在signal以前就已經釋放鎖了缺點:若是unlock和signal以前,有個低優先級的線程正在mutex上等待的話,那麼這個低優先級的線程就會搶佔高優先級的線程(cond_wait的線程),而這在上面的放中間的模式下是不會出現的。

相關文章
相關標籤/搜索