天天看點

條件變量的接口函數和使用原則 條件變量的接口、常量、資料類型 條件變量的使用原則

1.靜态建立一個條件變量(棧)

pthread_cond_t cond;

2.動态建立一個條件變量(堆)

pthread_cond_t * pCond = (pthread_cond_t *)malloc(sizeof(pthread_cond_t));

3.初始化靜态條件變量(預設方式)

使用宏 PTHREAD_COND_INITIALIZER

4.動态初始化條件變量

int pthread_init(pthread_cond_t *cond, pthread_condattr_t *condattr);

5.銷毀堆上建立的條件變量

int pthread_destroy(pthread_cond_t *cond);

6.使用條件變量進行等待

int pthread_cond_wait(pthread_cond_t * cond,pthread_mutex_t *mutex);

int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex_t *mutex,struct timespec * expiration);

7.喚醒條件變量

int pthread_cond_signal(pthread_cond_t * cond);

int pthread_cond_broadcast(pthread_cond_t * cond);

條件變量不允許複制,但是可以複制其指針。

線程從條件變量醒來時,一定要檢查謂語是否成立。這是因為以下三個原因造成的:

1.喚醒可能被攔截:線程A被喚醒的過程中需要重新擷取互斥量,如果互斥量被線程B首先擷取到了,則線程B首先執行并重置了共享資料的狀态,這時候切換回線程A,A在沒有檢查謂語成立的情況下開始操作可能導緻災難性的後果,因為此時謂語已經不成立。

2.模糊謂語:在程式中使用模糊謂語可簡化邏輯,而且并不會很影響性能。這種模糊謂語可能喚醒某個線程,該線程對應的精确謂語事實上是不滿足的,是以需要重新檢查謂語。

3.僞喚醒:這和實作相關了,保證條件變量的喚醒完全可預測可能降低系統的整體性能,線程可能在沒有任何其他線程使用signal或者broadcast的前提下喚醒,不過這種機率很小,但并不是沒有可能。

盡量不要再pthreads中使用UNIX信号。

發廣播可看成是對發信号通用化,也可見發信号看成是發廣播的優化版。不能使用發信号取代發廣播。在使用發信号的地方使用發廣播是完全可以的,當然前提是所有的喚醒線程都進行謂語測試。

對于一個隊列模型,如果有一個生産者,多個消費者。如果生産者一次隻放入一個産品,則可以使用發信号的方式。如果生産者一次放入多個産品則可以使用發廣播的方式。

在發廣播或者發信号的時候對于互斥量可以加鎖也可以不加鎖。不加鎖的好處為潛在的高效率,如果喚醒線程加鎖發信号,被喚醒的線程需要嘗試着擷取互斥量,這時擷取失敗,又切換回喚醒線程。這會導緻兩次無意義的切換,當然這個實作可以優化的。加鎖的好處在于保證高優先級的線程首先執行,如果不加鎖,則所有的線程(不隻是将要被喚醒的線程還可能有其他的沒有使用條件變量的線程)都有可能擷取目前鎖。如果低優先級的條件變量首先獲得了鎖,高優先級的線程将不能被保證。而使用加鎖的方式發廣播信号之後,解鎖後,系統會優先排程優先級高的線程先獲得鎖,是以保證了公平性(這裡的公平更接近于香港廉政署的定義:公平不是每個人都賺十塊錢,公平是你有賺100元的能力,社會保證你能賺100元。你有能力賺10元時,社會保證你賺10元 :D)。

本文轉自hipercomer 51CTO部落格,原文連結:http://blog.51cto.com/hipercomer/914921