條件變數變數也是出自posix
執行緒標準,另一種執行緒同步機制,。主要用來等待某個條件的發生。可以用來同步同一程序中的各個執行緒。當然如果乙個條件變數存放在多個程序共享的某個記憶體區中,那麼還可以通過條件變數來進行程序間的同步。
每個條件變數總是和乙個互斥量相關聯,條件本身是由互斥量保護的,執行緒在改變條件狀態之間必須要鎖住互斥量。條件變數相對於互斥量最大的優點在於允許執行緒以無競爭的方式等待條件的發生。當乙個執行緒獲得互斥鎖後,發現自己需要等待某個條件變為真,如果是這樣,該執行緒就可以等待在某個條件上,這樣就不需要通過輪詢的方式來判斷新增,大大節省了cpu
時間。
在互斥量一文中說過:互斥量是用於上鎖,而不是用於等待;現在這句話可以加強為:互斥量是用於上鎖,條件變數用於等待;
條件變數宣告為pthread_cond_t
資料型別,在
中有具體的定義。
1條件變數初始化和銷毀
/* initialize condition variable */
int pthread_cond_init (pthread_cond_t *__restrict __cond,
__const pthread_condattr_t *__restrict __cond_attr) ;
/* destroy condition variable */
int pthread_cond_destroy (pthread_cond_t *__cond);
上面兩個函式分別由於條件變數的初始化和銷毀。
和互斥量的初始化一樣,如果條件變數是靜態分配的,可以通過常量進行初始化,如下:
pthread_cond_t mlock = pthread_cond_initializer;
也可以通過pthread_cond_init()
進行初始化,對於動態分配的條件變數由於不能直接賦值進行初始化,就只能採用這種方式進行初始化。那麼當不在需要使用條件變數時,需要呼叫
pthread_cond_destroy()
銷毀該條件所占用的資源。
2條件變數的屬性設定
/* 初始化條件變數屬性物件 */
int pthread_condattr_init (pthread_condattr_t *__attr);
/* 銷毀條件變數屬性物件 */
int pthread_condattr_destroy (pthread_condattr_t *__attr);
/* 獲取條件變數屬性物件在程序間共享與否的標識 */
int pthread_condattr_getpshared (__const pthread_condattr_t * __restrict __attr,
int *__restrict __pshared);
/* 設定條件變數屬性物件,標識在程序間共享與否 */
int pthread_condattr_setpshared (pthread_condattr_t *__attr, int __pshared) ;
這個屬性的設定和互斥量屬性設定是一樣的,具體使用可以參考互斥量的用法:互斥量的屬性設定
。3條件變數的使用
/* 等待條件變為真 */
int pthread_cond_wait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex);
/* 限時等待條件為真 */
int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
__const struct timespec *__restrict __abstime);
/* 喚醒乙個等待條件的執行緒. */
int pthread_cond_signal (pthread_cond_t *__cond);
/* 喚醒等待該條件的所有執行緒 */
int pthread_cond_broadcast (pthread_cond_t *__cond);
(1
)pthread_cond_wait()函式用於等待條件被觸發。該函式傳入兩個引數,乙個條件變數乙個互斥量,函式將條件變數和互斥量進行關聯,互斥量對該條件進行保護,傳入的互斥量必須是已經鎖住的。呼叫
pthread_cond_wait()
函式後,會
原子的執行以下兩個動作:
由於這兩個操作時原子操作,這樣就關閉了條件檢查和執行緒進入睡眠等待條件改變這兩個操作之間的時間通道,這樣就不會錯過任何條件的變化。
當pthread_cond_wait()
返回後,互斥量會再次被鎖住。
(2)pthread_cond_timedwait()函式和pthread_cond_wait()的工作方式相似,只是多了乙個等待時間。等待時間的結構為
structtimespec
,
struct timespec;
函式要求傳入的時間值是乙個絕對值,不是相對值,例如,想要等待3
分鐘,必須先獲得當前時間,然後加上
3分鐘。
要想獲得當前系統時間的timespec
值,沒有直接可呼叫的函式,需要通過呼叫
gettimeofday
函式獲取
timeval
結構,然後轉換成
timespec
結構,轉換公式就是:
timespec.tv_sec = timeval.tv_sec;
timespec.tv_nsec = timeval.tv_usec * 1000;
所以要等待3
分鐘,timespec
時間結構的獲得應該如下所示
:
struct timeval now;
struct timespec until;
gettimeofday(&now);//獲得系統當前時間
//把時間從timeval結構轉換成timespec結構
until.tv_sec = now.tv_sec;
until.tv_nsec = now.tv_usec * 1000;
//增加min
until.tv_sec += 3 * 60;
如果時間到後,條件還沒有發生,那麼會返回etimedout
錯誤。
從pthread_cond_wait()和pthread_cond_timewait()成功返回時,執行緒需要重新計算條件,因為其他執行緒可能在執行過程中已經改變條件。
(3)pthread_cond_signal()&pthread_cond_broadcast()
這兩個函式都是用於向等待條件的執行緒傳送喚醒訊號,pthread_cond_signal()函式只會喚醒等待該條件的某個執行緒,pthread_cond_broadcast()會廣播條件狀態的改變,以喚醒等待該條件的所有執行緒。例如多個執行緒唯讀共享資源,這是可以將它們都喚醒。
這裡要注意的是:一定要在改變條件狀態後,再給執行緒傳送訊號。
考慮條件變數訊號單播發送和廣播傳送的一種候選方式是堅持使用廣播傳送。只有在等待者**編寫確切,只有乙個等待者需要喚醒,且喚醒哪個執行緒無所謂,那麼此時為這種情況使用單播,所以其他情況下都必須使用廣播傳送。
下面是乙個測試**,模擬同步問題中經典的生產者消費者問題。
#include #include #include #include #include using namespace std;
//把共享資料和它們的同步變數集合到乙個結構中,這往往是乙個較好的程式設計技巧。
structshareddata = ;
void * produce(void *ptr)
}void * consume(void *ptr)
{ for (int i = 0; i < 10;)
{pthread_mutex_lock(&shareddata.mutex);
while(shareddata.product.empty())
pthread_cond_wait(&shareddata.cond, &shareddata.mutex);
++i;
cout<<"consume:"《程式的執行結果如下所示:
consume:0
consume:1
consume:2
consume:3
consume:4
consume:5
consume:6
consume:7
consume:8
consume:9
jun 25, 2013 @library
Linux執行緒同步之條件變數
與互斥鎖不同,條件變數是用來等待而不是用來上鎖的。條件變數用來自動阻塞乙個執行緒,直到某特殊情況發生為止。通常條件變數和互斥鎖同時使用。條件變數使我們可以睡眠等待某種條件出現。條件變數是利用執行緒間共享的全域性變數進行同步的一種機制,主要包括兩個動作 乙個執行緒等待 條件變數的條件成立 而掛起 另乙...
Linux執行緒同步之 條件變數
條件變數是執行緒可用的另一種同步機制。條件變數給多執行緒提供了乙個會合的場所。它主要包括兩個動作 乙個執行緒等待 條件變數的條件成立 而掛起 另乙個執行緒使 條件成立 給出條件成立訊號 條件變數與互斥量一起使用時,允許執行緒以無競爭的方式等待特定的條件發生。條件變數本身是互斥量保護的。執行緒在改變條...
linux執行緒同步之條件變數
條件變數通過允許執行緒阻塞和等待另乙個執行緒傳送訊號的方法彌補了互斥鎖的不足,它常和互斥鎖一起使用。使用時,條件變數被用來阻塞乙個執行緒,當條件不滿足時,執行緒往往解開相應的互斥鎖並等待條件發生變化。一旦其它的某個執行緒改變了條件變數,它將通知相應的條件變數喚醒乙個或多個正被此條件變數阻塞的執行緒。...