1. 程式人生 > >linux下多執行緒中條件變數的用法

linux下多執行緒中條件變數的用法

使用條件變數最大的好處是可以避免忙等。相當與多執行緒中的訊號。 條件變數是執行緒中的東西就是等待某一條件的發生和訊號一樣

以下是說明
,條件變數使我們可以睡眠等待某種條件出現。
條件變數是利用執行緒間共享的全域性變數進行同步的一種機制,主要包括兩個動作:一個執行緒等待"條件變數的條件成立"而掛起;另一個執行緒使"條件成立"(給出條件成立訊號)。為了防止競爭,條件變數的使用總是和一個互斥鎖結合在一起。
條件變數型別為pthread_cond_t



建立和登出
條件變數和互斥鎖一樣,都有靜態動態兩種建立方式,靜態方式使用PTHREAD_COND_INITIALIZER常量,如下:
pthread_cond_t cond=PTHREAD_COND_INITIALIZER
動態方式呼叫pthread_cond_init()函式,API定義如下:
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
儘管POSIX標準中為條件變數定義了屬性,但在LinuxThreads中沒有實現,因此cond_attr值通常為NULL,且被忽略。
登出一個條件變數需要呼叫pthread_cond_destroy(),只有在沒有執行緒在該條件變數上等待的時候才能登出這個條件變數,否則返回EBUSY。API定義如下:
int pthread_cond_destroy(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)
等待條件有兩種方式:無條件等待pthread_cond_wait()和計時等待pthread_cond_timedwait(),其中計時等待方式如果在給定時刻前條件沒有滿足,則返回ETIMEOUT,結束等待,其中abstime以與time()系統呼叫相同意義的絕對時間形式出現,0表示格林尼治時間1970年1月1日0時0分0秒。
使用絕對時間而非相對時間的優點是。如果函式提前返回(很可能因為捕獲了一個訊號,)
無論哪種等待方式,都必須和一個互斥鎖配合,以防止多個執行緒同時請求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()則啟用所有等待執行緒。



其他
pthread_cond_wait()和pthread_cond_timedwait()都被實現為取消點,因此,在該處等待的執行緒將立即重新執行,在重新鎖定mutex後離開pthread_cond_wait(),然後執行取消動作。也就是說如果pthread_cond_wait()被取消,mutex是保持鎖定狀態的,因而需要定義退出回撥函式來為其解鎖。
EXAMPLE
       Consider two shared variables x and y, protected by the mutex mut,  and
       a  condition  variable  cond  that is to be signaled whenever x becomes
       greater than y.               int x,y;
              pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
              pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
   //    Waiting until x is greater than y is performed as follows:               pthread_mutex_lock(&mut);
              while (x <= y) {
                      pthread_cond_wait(&cond, &mut);
              }
              /* operate on x and y */
              pthread_mutex_unlock(&mut);
   //    Modifications on x and y that may cause x  to  become  greater  than  y
     //  should signal the condition if needed:               pthread_mutex_lock(&mut);
              /* modify x and y */
              if (x > y) pthread_cond_broadcast(&cond);
              pthread_mutex_unlock(&mut);
 /*      If  it  can be proved that at most one waiting thread needs to be waken
       up (for instance, if there are only two threads communicating through x
       and  y),  pthread_cond_signal  can be used as a slightly more efficient
       alternative    to    pthread_cond_broadcast.      In     doubt,     use
       pthread_cond_broadcast.        To  wait  for  x to becomes greater than y with a timeout of 5 seconds,
       do:  */                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) {
                      /* timeout occurred */
              } else {
                      /* operate on x and y */
              }
              pthread_mutex_unlock(&mut);
要想知道更詳細,請看  man pthread_cond_wait