轉自:http://blog.csdn.net/yeyuangen/article/details/37593533
僅供學習使用。。。
===============================man pthread_cond_wait的解釋==========================
LINUX環境下多線程編程肯定會遇到需要條件變量的情況,此時必然要使用pthread_cond_wait()函數。但這個函數的執行過程比較難於理解。
pthread_cond_wait()的工作流程如下(以MAN中的EXAMPLE爲例):
Consider two shared variables x and y, protected by the mutex mut, and a condition vari-
able 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 con-
dition if needed:
pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);
這個例子的意思是,兩個線程要修改X和 Y的值,第一個線程當X<=Y時就掛起,直到X>Y時才繼續執行(由第二個線程可能會修改X,Y的值,當X>Y時喚醒第一個線程),即 首先初始化一個普通互斥量mut和一個條件變量cond。之後分別在兩個線程中分別執行如下函數體:
pthread_mutex_lock(&mut);while (x <= y) {
pthread_cond_wait(&cond, &mut);
}
/* operate on x and y */
pthread_mutex_unlock(&mut);
和: pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mut);
其實函數的執行過程非常簡單,在第一個線程執行到pthread_cond_wait(&cond,&mut)時,此時如果X<=Y,則此函數就將mut互斥量解鎖 ,再將cond條件變量加鎖 ,此時第一個線程掛起 (不佔用任何CPU週期)。
而在第二個線程中,本來因爲mut被第一個線程鎖住而阻塞,此時因爲mut已經釋放,所以可以獲得鎖mut,並且進行修改X和Y的值,在修改之後,一個IF語句判定是不是X>Y,如果是,則此時pthread_cond_signal()函數會喚醒第一個線程 ,並在下一句中釋放互斥量mut。然後第一個線程開始從pthread_cond_wait()執行,首先要再次鎖mut ,
如果鎖成功,再進行條件的判斷 (至於爲什麼用WHILE,即在被喚醒之後還要再判斷,後面有原因分析),如果滿足條件,則被喚醒 進行處理,最後釋放互斥量mut 。
至於爲什麼在被喚醒之後還要再次進行條件判斷(即爲什麼要使用while循環來判斷條件),是因爲可能有“驚羣效應”。有人覺得此處既然是被喚醒的,肯定 是滿足條件了,其實不然。如果是多個線程都在等待這個條件,而同時只能有一個線程進行處理,此時就必須要再次條件判斷,以使只有一個線程進入臨界區處理。 對此,轉來一段:
引用下POSIX的RATIONALE:
Condition Wait Semantics
It is important to note that when pthread_cond_wait() and pthread_cond_timedwait() return without error, the associated predicate may still be false. Similarly, when pthread_cond_timedwait() returns with the timeout error, the associated predicate may be true
due to an unavoidable race between the expiration of the timeout and the predicate state change.
The application needs to recheck the predicate on any return because it cannot be sure there is another thread waiting on the thread to handle the signal, and if there is not then the signal is lost. The burden is on the application to check the predicate.
Some implementations, particularly on a multi-processor, may sometimes cause multiple threads to wake up when the condition variable is signaled simultaneously on different processors.
In general, whenever a condition wait returns, the thread has to re-evaluate the predicate associated with the condition wait to determine whether it can safely proceed, should wait again, or should declare a timeout. A return from the wait does not imply that
the associated predicate is either true or false.
It is thus recommended that a condition wait be enclosed in the equivalent of a "while loop" that checks the predicate.
從上文可以看出:
1,pthread_cond_signal在多處理器上可能同時喚醒多個線程,當你只能讓一個線程處理某個任務時,其它被喚醒的線程就需要繼續 wait,while循環的意義就體現在這裏了,而且規範要求pthread_cond_signal至少喚醒一個pthread_cond_wait上 的線程,其實有些實現爲了簡單在單處理器上也會喚醒多個線程.
2,某些應用,如線程池,pthread_cond_broadcast喚醒全部線程,但我們通常只需要一部分線程去做執行任務,所以其它的線程需要繼續wait.所以強烈推薦此處使用while循環.
其實說白了很簡單,就是pthread_cond_signal()也可能喚醒多個線程,而如果你同時只允許一個線程訪問的話,就必須要使用while來進行條件判斷,以保證臨界區內只有一個線程在處理。
==============================另一篇很好的文章===========================
==============================使用效率問題============================
我們假設系統中有線程1和線程2,他們都想獲取mutex後處理共享數據,再釋放mutex。請看這種序列:
1)線程1獲取mutex,在進行數據處理的時候,線程2也想獲取mutex,但是此時被線程1所佔用,線程2進入休眠,等待mutex被釋放。
2)線程1做完數據處理後,調用pthread_cond_signal()喚醒等待隊列中某個線程,在本例中也就是線程2。線程1在調用pthread_mutex_unlock()前,因爲系統調度的原因,線程2獲取使用CPU的權利,那麼它就想要開始處理數據,但是在開始處理之前,mutex必須被獲取,很遺憾,線程1正在使用mutex,所以線程2被迫再次進入休眠。
3)然後就是線程1執行pthread_mutex_unlock()後,線程2方能被再次喚醒。
從這裏看,使用的效率是比較低的,如果再多線程環境中,這種情況頻繁發生的話,是一件比較痛苦的事情。