為了解決這個問題骆捧,首先要非常深入了解每一個概念:
1. 互斥鎖(mutual exclusive lock variable / mutex )
互斥量(mutex)從本質(zhì)上說是一把鎖,在訪問共享資源前對互斥量進行加鎖髓绽,在訪問完成后釋放互斥量上的鎖敛苇。對互斥量進行加鎖以后,任何其他試圖再次對互斥鎖加鎖的線程將會阻塞直到當前線程釋放該互斥鎖顺呕。如果釋放互斥鎖時有多個線程阻塞枫攀,所有在該互斥鎖上的阻塞線程都會變成可運行狀態(tài),第一個變?yōu)檫\行狀態(tài)的線程可以對互斥鎖加鎖株茶,其他線程將會看到互斥鎖依然被鎖住来涨,只能回去再次等待它重新變?yōu)榭捎谩?/strong>
2. 條件變量
條件變量(cond)是在多線程程序中用來實現(xiàn)"等待--》喚醒"邏輯常用的方法。條件變量利用線程間共享的全局變量進行同步的一種機制启盛,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起蹦掐;另一個線程使“條件成立”。為了防止競爭僵闯,條件變量的使用總是和一個互斥鎖結(jié)合在一起卧抗。線程在改變條件狀態(tài)前必須首先鎖住互斥量,函數(shù)pthread_cond_wait把自己放到等待條件的線程列表上鳖粟,然后對互斥鎖解鎖(這兩個操作是原子操作)社裆。在函數(shù)返回時,互斥量再次被鎖住向图。
那為什么有互斥鎖泳秀,還需要條件變量?
因為:互斥鎖和條件變量所解決的张漂,是不同的問題晶默,不同的場景。
互斥鎖解決的是在 shared memory space 模型下航攒,多個線程對同一個全局變量的訪問的競爭問題磺陡。由于寫操作的非原子性(從內(nèi)存中讀進寄存器,修改漠畜,如果其他線程完成了對這個變量的修改币他,則舊的修改就被覆蓋,等等問題)憔狞,必須保證同一時間只有一個線程在進行寫操作蝴悉。這就涉及到了互斥鎖,將臨界區(qū)的操作鎖起來瘾敢,保證只有一個線程在進行操作拍冠。多個線程在等待同一把鎖的時候尿这,按照 FIFO 組織隊列,當鎖被釋放時庆杜,隊頭線程獲得鎖(由操作系統(tǒng)管理射众,具體不表)。沒有獲得鎖的線程繼續(xù)被 block晃财,換言之叨橱,它們是因為沒有獲得鎖而被 block。
假如我們沒有“條件變量”這個概念断盛,如果一個線程要等待某個“自定義的條件”滿足而繼續(xù)執(zhí)行罗洗,而這個條件只能由另一個線程來滿足,比如 T1不斷給一個全局變量 x +1钢猛, T2檢測到x 大于100時伙菜,將x 置0,如果我們沒有條件變量命迈,則只通過互斥鎖則可以有如下實現(xiàn):
/*
* Assume we have global variables:
* int iCount == 0;
* pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
*/
//thread 1:
while(true)
{
pthread_mutex_lock(&mutex);
iCount++;
pthread_mutex_unlock(&mutex);
}
//thread 2:
while(true)
{
pthread_mutex_lock(&mutex);
if(iCount >= 100)
{
iCount = 0;
}
pthread_mutex_unlock(&mutex);
}
這種實現(xiàn)下仇让,就算 lock 空閑,thread2需要不斷重復<加鎖躺翻,判斷丧叽,解鎖>這個流程,會給系統(tǒng)帶來不必要的開銷公你。有沒有一種辦法讓 thread2先被 block踊淳,等條件滿足的時候再喚醒 thread2?這樣 thread2 就不用不斷進行重復的加解鎖操作了陕靠?這就要用到條件變量了:
//thread1 :
while(true)
{
pthread_mutex_lock(&mutex);
iCount++;
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex);
if(iCount >= 100)
{
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
}
//thread2:
while(1)
{
pthread_mutex_lock(&mutex);
while(iCount < 100)
{
pthread_cond_wait(&cond, &mutex);
}
printf("iCount >= 100\r\n");
iCount = 0;
pthread_mutex_unlock(&mutex);
}
需要注意的是迂尝,條件變量需要配合互斥鎖來使用:
為什么要與pthread_mutex 一起使用呢? 這是為了應(yīng)對 線程1在調(diào)用pthread_cond_wait()但線程1還沒有進入wait cond的狀態(tài)的時候剪芥,此時線程2調(diào)用了 cond_singal 的情況垄开。 如果不用mutex鎖的話,這個cond_singal就丟失了税肪。加了鎖的情況是溉躲,線程2必須等到 mutex 被釋放(也就是 pthread_cod_wait() 釋放鎖并進入wait_cond狀態(tài) ,此時線程2上鎖) 的時候才能調(diào)用cond_singal.
簡而言之就是益兄,在thread 1 call pthread_cond_wait() 的時刻到 thread 1真正進入 wait 狀態(tài)時锻梳,是存在著時間差的。如果在這段時間差內(nèi) thread2 調(diào)用了 pthread_cond_signal() 那這個 signal 信號就丟失了净捅。給 wait 加鎖可以防止同時有另一個線程在 signal疑枯。
(好像還有其他原因,有空補蛔六。)