信號量與條件變量的區別

注意信號量與條件變量的區別

信號量內容可見:http://www.cnblogs.com/charlesblc/p/6142868.html
 
信號量、共享內存,以及消息隊列等System V IPC三劍客主要關注 進程間通訊
而條件變量、互斥鎖,主要關注 線程間通訊
 
 
pthread_cond_wait指的是 條件變量,總和一個 互斥鎖結合使用。在 調用pthread_cond_wait前要先獲取鎖。pthread_cond_wait函數執行時先 自動釋放指定的鎖,而後等待條件變量的變化。在函數調用返回以前,自動將指定的互斥量 從新鎖住
 

int pthread_cond_signal(pthread_cond_t * cond);html

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_MUTEX_TIMED_NP,這是缺省值,也就是普通鎖。當一個線程加鎖之後,其他請求鎖的線程將造成一個等待隊列,並在解鎖後按優先級得到鎖。這種鎖策略保證了資源分配的公平性。

  PTHREAD_MUTEX_RECURSIVE_NP,嵌套鎖,容許同一個線程對同一個鎖成功得到屢次,並經過屢次unlock解鎖。若是是不一樣線程請求,則在加鎖線程解鎖時從新競爭。

  PTHREAD_MUTEX_ERRORCHECK_NP,檢錯鎖,若是同一個線程請求同一個鎖,則返回EDEADLK,不然與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加鎖?ui

瞭解 pthread_cond_wait() 的做用很是重要 -- 它是 POSIX 線程信號發送系統的核心,也是最難以理解的部分。
首先,讓咱們考慮如下狀況:線程爲查看已連接列表而鎖定了互斥對象,然而該列表恰巧是空的。這一特定線程什麼也幹不了 -- 其設計意圖是從列表中除去節點,可是如今卻沒有節點。所以,它只能:

鎖定互斥對象時,線程將調用 pthread_cond_wait(&mycond,&mymutex)。
 
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() 調用中)如今將 甦醒是先解鎖仍是先signal,各有優缺點,下文會分析另外注意,signal的函數裏面是否是解鎖加鎖的,跟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 一塊兒使用呢?spa

這是爲了應對 線程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
    xxxxxxx
pthread_cond_signal
pthread_mutex_unlock
缺點:在某下線程的實現中,會形成等待線程從內核中喚醒(因爲cond_signal)而後又回到內核空間(由於 cond_wait返回後會有原子加鎖的 行爲)(注:意思是說這時候signal的線程尚未unlock,因此wait的線程加鎖會致使堵塞,並進入內核),因此一來一回會有性能的問題。可是在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的線程),而這在上面的放中間的模式下是不會出現的。
相關文章
相關標籤/搜索