在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做爲緩衝隊列
的線程,會出現上述註釋出現的狀況,形成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來進行條件判斷,以保證臨界區內只有一個線程在處理