有了互斥鎖,為什么還要條件變量?

為了解決這個問題,首先要非常深入了解每一個概念:

1. 互斥鎖(mutual exclusive lock variable / mutex )

互斥量(mutex)從本質上說是一把鎖,在訪問共享資源前對互斥量進行加鎖,在訪問完成后釋放互斥量上的鎖。對互斥量進行加鎖以后,任何其他試圖再次對互斥鎖加鎖的線程將會阻塞直到當前線程釋放該互斥鎖。如果釋放互斥鎖時有多個線程阻塞,所有在該互斥鎖上的阻塞線程都會變成可運行狀態(tài),第一個變?yōu)檫\行狀態(tài)的線程可以對互斥鎖加鎖,其他線程將會看到互斥鎖依然被鎖住,只能回去再次等待它重新變?yōu)榭捎谩?/strong>

2. 條件變量

條件變量(cond)是在多線程程序中用來實現(xiàn)"等待--》喚醒"邏輯常用的方法。條件變量利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使“條件成立”。為了防止競爭,條件變量的使用總是和一個互斥鎖結合在一起。線程在改變條件狀態(tài)前必須首先鎖住互斥量,函數(shù)pthread_cond_wait把自己放到等待條件的線程列表上,然后對互斥鎖解鎖(這兩個操作是原子操作)。在函數(shù)返回時,互斥量再次被鎖住。

那為什么有互斥鎖,還需要條件變量?

因為:互斥鎖和條件變量所解決的,是不同的問題,不同的場景。

互斥鎖解決的是在 shared memory space 模型下,多個線程對同一個全局變量的訪問的競爭問題。由于寫操作的非原子性(從內存中讀進寄存器,修改,如果其他線程完成了對這個變量的修改,則舊的修改就被覆蓋,等等問題),必須保證同一時間只有一個線程在進行寫操作。這就涉及到了互斥鎖,將臨界區(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 一起使用呢? 這是為了應對 線程1在調用pthread_cond_wait()但線程1還沒有進入wait cond的狀態(tài)的時候,此時線程2調用了 cond_singal 的情況。 如果不用mutex鎖的話,這個cond_singal就丟失了。加了鎖的情況是,線程2必須等到 mutex 被釋放(也就是 pthread_cod_wait() 釋放鎖并進入wait_cond狀態(tài) ,此時線程2上鎖) 的時候才能調用cond_singal.

簡而言之就是,在thread 1 call pthread_cond_wait() 的時刻到 thread 1真正進入 wait 狀態(tài)時,是存在著時間差的。如果在這段時間差內 thread2 調用了 pthread_cond_signal() 那這個 signal 信號就丟失了。給 wait 加鎖可以防止同時有另一個線程在 signal。

(好像還有其他原因,有空補。)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 前言 在多線程開發(fā)中,常會遇到多個線程訪問修改數(shù)據(jù)。為了防止數(shù)據(jù)不一致或數(shù)據(jù)污染,通常采用加鎖機制來保證線程安全。...
    趙夢楠閱讀 1,160評論 0 5
  • 引用自多線程編程指南應用程序里面多個線程的存在引發(fā)了多個執(zhí)行線程安全訪問資源的潛在問題。兩個線程同時修改同一資源有...
    Mitchell閱讀 2,119評論 1 7
  • linux線程同步 信號燈:與互斥鎖和條件變量的主要不同在于"燈"的概念,燈亮則意味著資源可用,燈滅則意味著不可用...
    鮑陳飛閱讀 752評論 0 2
  • 簡介 線程創(chuàng)建 線程屬性設置 線程參數(shù)傳遞 線程優(yōu)先級 線程的數(shù)據(jù)處理 線程的分離狀態(tài) 互斥鎖 信號量 一 線程創(chuàng)...
    第八區(qū)閱讀 8,712評論 1 6
  • 成功的路,不怕萬人阻擋,只怕自己投降;成長的帆,不怕狂風巨浪,只怕自己沒膽量!有路,就大膽去走;有夢,就大膽飛翔。...
    安全保衛(wèi)處閱讀 315評論 0 0

友情鏈接更多精彩內容