1. 相關函數
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t
*cond_attr);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t
*mutex, const struct timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);
2. 說明
條件變數是一種同步機制,允許線程掛起,直到共用資料上的某些條件得到滿足。條件變數上的基本操作有:觸發條件(當條件變為 true 時);等待條件,掛起線程直到其他線程觸發條件。
條件變數要和互斥量相連接,以避免出現條件競爭--一個線程預備等待一個條件變數,當它在真正進入等待之前,另一個線程恰好觸發了該條件。
pthread_cond_init 使用 cond_attr 指定的屬性初始化條件變數 cond,當 cond_attr 為 NULL 時,使用預設的屬性。LinuxThreads 實現條件變數不支援屬性,因此 cond_attr 參數實際被忽略。
pthread_cond_t 類型的變數也可以用 PTHREAD_COND_INITIALIZER 常量進行靜態初始化。
pthread_cond_signal 使在條件變數上等待的線程中的一個線程重新開始。如果沒有等待的線程,則什麼也不做。如果有多個線程在等待該條件,只有一個能重啟動,但不能指定哪一個。
pthread_cond_broadcast 重啟動等待該條件變數的所有線程。如果沒有等待的線程,則什麼也不做。
pthread_cond_wait 自動解鎖互斥量(如同執行了 pthread_unlock_mutex),並等待條件變數觸發。這時線程掛起,不佔用 CPU 時間,直到條件變數被觸發。在調用 pthread_cond_wait 之前,應用程式必須加鎖互斥量。pthread_cond_wait 函數返回前,自動重新對互斥量加鎖(如同執行了 pthread_lock_mutex)。
互斥量的解鎖和在條件變數上掛起都是自動進行的。因此,在條件變數被觸發前,如果所有的線程都要對互斥量加鎖,這種機制可保證線上程加鎖互斥量和進入等待條件變數期間,條件變數不被觸發。
pthread_cond_timedwait 和 pthread_cond_wait 一樣,自動解鎖互斥量及等待條件變數,但它還限定了等待時間。如果在 abstime 指定的時間內 cond 未觸發,互斥量 mutex 被重新加鎖,且 pthread_cond_timedwait 返回錯誤 ETIMEDOUT。abstime 參數指定一個絕對時間,時間原點與 time 和 gettimeofday 相同:abstime = 0 表示 1970 年 1 月 1 日 00:00:00 GMT。
pthread_cond_destroy 銷毀一個條件變數,釋放它擁有的資源。進入 pthread_cond_destroy 之前,必須沒有在該條件變數上等待的線程。在 LinuxThreads 的實現中,條件變數不連接資源,除檢查有沒有等待的線程外,pthread_cond_destroy 實際上什麼也不做。
3. 取消
pthread_cond_wait 和 pthread_cond_timedwait 是取消點。如果一個線程在這些函數上掛起時被取消,線程立即繼續執行,然後再次對 pthread_cond_wait 和 pthread_cond_timedwait 在 mutex 參數加鎖,最後執行取消。因此,當調用清除處理常式時,可確保,mutex 是加鎖的。
4. 非同步訊號安全(Async-signal Safety)
條件變數函數不是非同步訊號安全的,不應當在訊號處理常式中進行調用。特別要注意,如果在訊號處理常式中調用 pthread_cond_signal 或 pthread_cond_boardcast 函數,可能導致調用線程死結。
5. 傳回值
在執行成功時,所有條件變數函數都返回 0,錯誤時返回非零的錯誤碼。
6. 錯誤碼
pthread_cond_init, pthread_cond_signal, pthread_cond_broadcast, 和 pthread_cond_wait 從不返回錯誤碼。
pthread_cond_timedwait 函數出錯時返回下列錯誤碼:
ETIMEDOUT abstime 指定的時間逾時時,條件變數未觸發
EINTR pthread_cond_timedwait 被觸發中斷
pthread_cond_destroy 函數出錯時返回下列錯誤碼:
EBUSY 某些線程正在等待該條件變數
7. 舉例
設有兩個共用的變數 x 和 y,通過互斥量 mut 保護,當 x > y 時,條件變數 cond 被觸發。
int x,y;
int x,y;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
等待直到 x > y 的執行流程:
pthread_mutex_lock(&mut);
while (x <= y) {
pthread_cond_wait(&cond, &mut);
}
/* 對 x、y 進行操作 */
pthread_mutex_unlock(&mut);
對 x 和 y 的修改可能導致 x > y,應當觸發條件變數:
pthread_mutex_lock(&mut);
/* 修改 x、y */
if (x > y) pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);
如果能夠確定最多隻有一個等待線程需要被喚醒(例如,如果只有兩個線程通過 x、y 通訊),則使用 pthread_cond_signal 比 pthread_cond_broadcast 效率稍高一些。如果不能確定,應當用 pthread_cond_broadcast。
要等待在 5 秒內 x > y,這樣處理:
struct timeval now;
struct timespec timeout;
int retcode;
pthread_mutex_lock(&mut);
gettimeofday(&now);
timeout.tv_sec = now.tv_sec + 5;
timeout.tv_nsec = now.tv_usec * 1000;
retcode = 0;
while (x <= y && retcode != ETIMEDOUT) {
retcode = pthread_cond_timedwait(&cond, &mut, &timeout);
}
if (retcode == ETIMEDOUT) {
/* 發生逾時 */
} else {
/* 操作 x 和 y */
}
pthread_mutex_unlock(&mut);
原文地址 http://blog.csdn.net/hiflower/archive/2008/03/18/2195350.aspx