關於pthread_cond_wait使用while循環判斷的理解

 
 

在Stevens的《Unix 環境高級編程》中第11章線程關於pthread_cond_wait的介紹中有一個生產者-消費者的例子P311,
在進入pthread_cond_wait前使用while進行條件判斷,而沒有直接使用if,耐人費解!編程

代碼以下:

#include <pthread.h>
struct msg {
  struct msg *m_next;
  /* value...*/
};

struct msg* workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;

void
process_msg() {
  struct msg* mp;
  for (;;) {
    pthread_mutex_lock(&qlock);
    while (workq == NULL) {
      pthread_cond_wait(&qread, &qlock);
    }
    mq = workq;
    workq = mp->m_next;
    pthread_mutex_unlock(&qlock);
    /* now process the message mp */
  }
}

void
enqueue_msg(struct msg* mp) {
    pthread_mutex_lock(&qlock);
    mp->m_next = workq;
    workq = mp;
    pthread_mutex_unlock(&qlock);
    /** 此時另一個線程在signal以前,執行了process_msg,恰好把mp元素拿走*/
    pthread_cond_signal(&qready);
    /** 此時執行signal, 在pthread_cond_wait等待的線程被喚醒,
         可是mp元素已經被另一個線程拿走,因此,workq仍是NULL ,所以須要繼續等待*/
}

這裏process_msg至關於消費者,enqueue_msg至關於生產者,struct msg* workq做爲緩衝隊列
 
 

解釋以下

在process_msg中使用while(workq==NULL)循環判斷條件,這裏主要是由於在enqueue_msg中unlock以後才喚醒等待

的線程,會出現上述註釋出現的狀況,形成workq==NULL,所以須要繼續等待。函數

可是若是將pthread_cond_signal移到pthread_mutex_unlock()以前執行,則會避免這種競爭,在unlockspa

以後,會首先喚醒pthread_cond_wait的線程,進而workq!=NULL老是成立。.net

pthread_cond_wait返回時沒法保證判斷式是真是假,所以須要從新判斷。所以建議使用while循環進行驗證,以便可以容忍這種競爭。線程

http://yaronspace.cn/blog/archives/1479code

 

還有一種解釋以下所示blog

http://bbs.csdn.net/topics/370094313隊列

我猜應該是這個意思:
假設有兩個線程(我就用僞代碼了):
//thread 1
while(0<x<10)
    pthread_cond_wait();

//thread 2
while(5<x<15)
    pthread_cond_wait();

若是某段時間內 x == 8,那麼兩個線程相繼進入等待。

而後,另外一個線程3:
修改x:x = 12
if(..) phtread_cond_signal()

那麼,雖然線程一、2都被喚醒了,可是,此時線程1仍然不知足while,只有線程1跳出while,
咱們假設一種狀況線程2線得到了鎖,而後發現知足循環條件,以後又有執行pthread_cond_wait()函數,而後阻塞在這兒,而且釋放鎖!
1,pthread_cond_signal在多處理器上可能同時喚醒多個線程,當你只能讓一個線程處理某個任務時,其它被喚醒的線程就須要繼續wait,while循環的意義就體如今這裏了,並且規範要求pt   hread_cond_signal至少喚醒一個pthread_cond_wait上的線程,其實有些實現爲了簡單在單處理器上也會喚醒多個線程. 
2,某些應用,如線程池,pthread_cond_broadcast喚醒所有線程,但咱們一般只須要一部分線程去作執行任務,因此其它的線程須要繼續wait.因此強烈推薦此處使用while循環.
  其實說白了很簡單,就是pthread_cond_signal()也可能喚醒多個線程,而若是你同時只容許一個線程訪問的話,就必需要使用while來進行條件判斷,以保證臨界區內只有一個線程在處理
相關文章
相關標籤/搜索