1. 程式人生 > >條件變數(condition variable)詳解

條件變數(condition variable)詳解

原理:

   假設我們需要解決這樣一個問題:一個列表記錄需要處理的任務。一個執行緒往此列表新增任務,一個執行緒processTask處理此列表中的任務。這個問題的一個關鍵點在於processTask怎麼判斷任務列表不為空。一般有兩種方法: 
   **一. processTask執行緒不斷查詢任務列表是否為空。**
   **二. 當列表不為空的時候,通知processTask處理相關任務。**

   第一種方法往往是在一個while迴圈中判斷列表是否為空,如果為空則睡眠一段時間,如果不為空那麼把任務取出來並加以處理。此方案需要一個睡眠時間的平衡點如果睡眠時間太長,任務得不到及時的處理,降低效率。如果睡眠時間過短佔用CPU資源,卻什麼都不做,浪費CPU做其它事情的時間。
   第二種方法就比較靠譜了,只有當列表不為空的時候才佔用CPU的時間,其它時間什麼都不做除了睡覺(執行緒掛起)。此方案就是我們所說的條件變數(condition variable)。 

   一般條件變數(condition variable)和互斥量結合使用。條件變數(condition variable)用途執行緒間資源的同步,互斥量(mutex)用途資源的互斥(唯一訪問)。 一個通俗易懂的例子: 你上廁所的時候,條件變數告訴你廁所是否為空位,有空位你上,沒空位你看著別人上。有空位的時候你不可能跟別人一起吧,所以你得給衛生間上鎖也就是互斥量了。 

 例:
  bool bathroomEmpty = false;
  pthread_t tid;
  pthread_cond_t cond;
  pthread_mutex_t mutex;

  void* takeAleak(void *) {
    pthread_mutex_lock(&mutex);
     while (!bathroomEmpty) 
       pthread_cond_wait(&cond, &mutex);
    // do whatever you want
     pthread_mutex_unlock(&mutex);
  }

  void
main() { pthread_mutex_lock(&mutex); // bathromm is empty now. bathroomEmpty = true; pthread_mutex_unlock(&mutex); // tell somebody pthread_cond_signal(&cond); return 0; }
   有些人不禁會問為什麼要while (!bathroomEmpty), 而不用if (!bathroomEmpty)呢?那是因為當你醒過來後,發現廁所已經被佔了,那麼你還得繼續等。

   pthread_cond_signal(&cond),可不可以放入pthread_mutex_unlock(&mutex)之前呢,答案是肯定的,只要保證通知別人的時候廁所已經空了。之前我們已經說了,你醒過來的時候廁所可能已經被佔了,那麼如何能保證你在醒來的時候廁所還是空的呢,那就把pthread_cond_signal(&cond)放在pthread_mutex_unlock(&mutex)之前吧。

   可能你已經發現了,pthread_cond_wait()函式還需要將mutex變數傳入。是的,pthread_cond_wait()函式在等待之前會把互斥鎖開啟,以便其它執行緒向任務表裡面新增任務。在等到任務後再加上鎖。如果不把互斥鎖開啟,那麼執行緒將永遠等不到任務,加上了鎖,其它執行緒就沒法往任務列表裡面新增任務了,因為其它執行緒新增任務的時候需要擁有鎖。

broadcast(&cond), 與signal(&cond)的區別

   顧名思義pthread_cond_broadcast喚醒所有的執行緒,pthread_cond_signal喚醒一個執行緒。你等待上廁所的同時也有其它人在等待,pthread_cond_signal通知你們其中的一人,pthread_cond_broad_cast通知你們所有人。當所有人被通知又只有一個空位的時候,你們所有人蜂擁而上,當然只能有一個人搶到空位,其它人繼續等。這就是為什麼要用while (!bathroomEmpty),而非if (!bathroomEmpty) 的原因了。當一個的人時候,其它人並不知道,所以不會發生通知所有人的競態條件。當只有一個空位的時候用pthread_cond_broad_cast,當有多個空位的時候用pthread_cond_broadcast。遺憾沒有通知具體人數的函式。