日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux C语言多线程库pthread中条件变量的正确用法逐步详解

發布時間:2025/3/15 linux 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux C语言多线程库pthread中条件变量的正确用法逐步详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

linux C語言多線程庫pthread中條件變量的正確用法:

了解pthread常用多線程API和pthread互斥鎖,但是對條件變量完全不知道或者不完全了解的人群。

關于條件變量的典型應用,可以參考非常精簡的linux線程池實現(一)--使用互斥鎖和條件變量。

但是如果對條件變量不熟悉的請看本文。

pthread庫的條件變量機制的主要API有三個:

int pthread_cond_wait(pthread_cond_t *cond , pthread_mutex_t *mutex);

int ptheead_cond_broadcast(pthread_cond_t *cond);

int pthread_cond_signal(pthread_cond_t *cond);

注意:還有一個沒說的API是pthread_cond_timedwait(),他跟pthread_cond_wait的唯一不同就是可以指定一個等待的超時時間,這里不對他做討論。

他們和其他幾個pthread API 一起用于處理一種特定的情形的線程同步問題:

1、若干個線程在某個條件沒有滿足時不能繼續往下面走,于是紛紛調用pthread_cond_wait使自己在這個條件上陷入等待(休眠)。?

2、當條件滿足之后,另外有個活躍著的線程調用pthread_cond_broadcast()通知喚醒那些等待在這個條件上的線程,讓他們繼續往下執行。

這種情形是非常基礎的,很多更加具體的線程同步問題都是這種情形的擴展,比如說經典的消費者/生產者問題,讀者/寫者問題等等。明顯“條件”是這種情形的核心,所以pthread得這套線程同步機制叫做“條件變量”。可以看出條件變量機制跟java的wait/notify費唱類似。

?

條件變量通過 pthread_cond_t 數據類型來聲明,而且使用之前要初始化:

pthread_cond_t cond =PTHREAD_COND_INITIALIZER;

上面這種是通過預定義的初始化宏來靜態初始化,也可以用函數動態初始化:

? pthread_cond_t cond;

pthread_cond_init(&cond,NULL);

?

注意條件聲明為全局可見的,因為條件變量會在多個線程的函數中被訪問。條件變量最后不再使用了的時候,應該銷毀。

pthread_cond_destroy(&cond);

在初始化后到銷毀前這段時間內就是條件變量的正常生命周期了,可以按需要對他調用 pthread_cond_wait(),pthread_cond_signal(), pthread_cond_broadcast().

?

pthread_cond_signal()的作用和pthread_cond_broadcast相似,但不同的是pthread_cond_signal會通知所有等待的線程中至少一個,讓他們繼續往下執行,而所有其他沒被通知的等待的線程則繼續等待(休眠)。之所以pthread_cond_wait()也可能因為各種原因自動返回,比如說信號中斷。

?

但是實際應用場景中我們每調用一次pthread_cond_signal 就喚醒一個等待線程:

1 某個線程專門負責從網絡接收數據包,其它若干線程專門負責處理數據包。當沒有任何數據包時,處理線程全部調用pthread_cond_wait陷入等待。當一個數據包到達時,接收線程調用phtread_cond_signal喚醒一個處理線程,處理線程拿走這個數據包去處理。當又一個數據包到達時,接收線程再次調用pthread_cond_signal喚醒一個線程……

這個問題對信號量機制來說很容易,因為信號量中的sem_post函數只會喚醒一個等待的進程或線程。雖然,pthread_cond_signal本身不保證只喚醒一個等待線程,但是POSIX標準在定義這套API時候考慮了這個問題,他留了一個后門,讓我們在應用程序中可以通過額外的代碼來解決這個問題。

?

先不考慮,那個后門,一個看上去可行的辦法就是,除了條件變量意外,在額外設置一個全局的普通計數變量表示允許喚醒多少個等待的線程:

int globle_count = 0;

嗎,那么當通知線程需要調用pthread_cond_signal喚醒別的線程之前,因該先增加全局變量的計數,表示允許喚醒的線程數目又增加了一個:

gloable++

pthread_cond_signal(&cond);

?

pthread_cond_signal一旦調用,那些調用pthread_cond_wait等待在cond的線程可能會有好幾個都會喚醒,假設全部喚醒了。其實我 ?們只想染一個繼續往下走,其他的不應該往下走,那么其他那些等待線程就都應該再次調用pthread_cond_wait繼續等待(這里應該有個循環)。

?

下面的問題就是,怎么決定那個等待線程繼續走哪?可以這樣,當大家都被喚醒的時候,大家都判斷一下 global_count 是不是大于0,也就是當前允不允許喚醒線程。如果某個等待線程檢測到的gloable_count是大于0的,就趕緊把gloable_count減掉一個,然后自己往下走。這時候gloable_count少了一個,可能就是0了,表示不允許在喚醒線程,其他幾個等待線程發現這一狀況后不往下走了,再次調用pthread_cond_wait)表示繼續等待:

?

while(gloable<=0)

{

pthread_cond_wait(&cond,&mutex);

}

gloable -=1;

到現在為止問題基本解決了,但是引出了一個新的問題:多個線程同時訪問gloable_count變量會造成競態條件。問題看上去很容易解決,使用互斥鎖就好了。

對于通知線程:

pthread_mutex_lock(&mutex);

gloable_count+=1;

pthread_cond_signal(&cond);

pthread_mutex_unlock(&mutex);

對于等待線程:

pthread_metex_lock(&mutex);

while(gloable_count<=0)

{

pthread_cond_wait(&cond,&mutex);

}

gloable_count - =1;

pthread_mutex_unlock(&mutex);

新的問題又來啦:等待線程調用pthread_cond_wait()陷入等待時,還占有著mutex互斥鎖,下次通知線程下次想要喚醒線程時就無法獲取mutex互斥鎖了,

于是就會出現死鎖。所以在調用pthread_cond——wait將當前線程陷入等待之前我們應該揭開互斥鎖,當線程被喚醒時,從pthread_cond_wait函數返回時,我們因該重新獲取互斥鎖。

比如像這樣:

pthread_mutex_lock(&mutex);

while(gloable_count<=0)

{

pthread_mutex_unlock(&mutex);

pthread_cond_wait(&cond,&mutex);

pthread_mutex_lock(&mutex);

}

gloable_count-=1;

pthread_mutex_unlock(&mutex);

?

這段代碼還是有問題的,在pthread_cond_wait函數調用前后當前線程都有一段看上去很短的不擁有mutex互斥鎖的真空期,但是對于cpu來說這段真空期并不算太短。

假設某個等線程檢測到gloable_count == 0 ,于是解開mutex互斥鎖,進入真空期,即將調用pthread_cond_wait()。就在這個時候,通知線程增加了一下gloable_count的技術值然后調用了pthread_cond_signal。接下來,剛才那個等待線程調用pthread_cond_wait陷入等待,由于pthread_cond_wait的調用發生在pthread_signal之后,所以pthread_cond_wait并不會返回。如果程序里的等待線程就這一個,這個通知就丟失了。

?

問題到了這里似乎沒路可走了,但是別忘了還有個后門沒用上,那就是前面一直沒提到的pthread_cond_wait 的第二個參數。第二個參數赫然是mutex!這下猜也能猜到這第二個參數是干什么的了,明顯就是專門幫我們解開mutex鎖啊。然后在pthread_cond_wait返回之前自動獲取mutex鎖。在這里順道澄清一下,和條件變量關聯的mutex,不是向網上部分人說到的那樣是用來保護條件變量的,條件變量在實現的時候,是能夠在實現的時候是能夠做到線程安全的,因為他內部還有一個自己的互斥鎖。

所以正確的做法是:

pthread_mutex_lock(&mutex);

while(gloable_count<=0)

{

pthread_cond_wait(&cond,&mutex);

}

gloable_count-=1;

pthread_mutex_unlock(&mutex);

到這里問題是不是完全解決了?很遺憾,還差一點,pthread_cond_wait是線程撤銷點之一,這意味著當某個線程因為調用pthread_cond_wait()而陷入休眠等待時,別的縣城可以通過這個縣城的id調用pthread_cancel讓這個線程強制從pthread_cond_wait返回并開始執行一些清理工作,最后結束而退出。

?

問題就出在pthread_cond_wait返回上,上面標紅的地方已經被強調了,pthread_cond_wait返回之前會先自動獲取mutex,也就是說返回以后已經占有了mutex互斥所。這種情況下,線程直接退出會導致互斥鎖一直被占用,其他線程就無法獲取這個互斥鎖了,再次出現死鎖。

這個問題有兩種解決辦法:

(1)線程退出前的清理工作中加入解開互斥鎖的代碼,這個并不難辦到,用為POSIX定義了兩個API:

void pthread_cleanup_pop(int execute);

void pthread_cleanup_push(void * (*routine)(void*),void * arg);

?

pthread_cleanup_push(),用于像一個特殊棧壓入一個函數指針,當線程退出時候,這個特殊站中的所有函數都會被一個個從堆棧頂彈出并執行(return 退出的情況除外)。pthread_cleanup_pop()用于從這個特殊堆棧的堆棧頂手動彈出函數指針,execute參數非0 ,彈出的函數會被自動執行。

需要注意的是,POSIX標準允許這兩個API被實現為帶未閉合花括號的宏,所以這兩個API一定(最好)要配套使用:它們必須一前一后(push在前),而且在同一個函數的同一個嵌套層次內。

比如說這兩個API的實現有可能會是類似于這樣:

所以這就是為什么它們的調用要求如此奇怪了。
有了這兩個API,想要解決剛才的問題,首先要定義一個清理回調函數:

void mutex_clean(void * mutex)

{

pthread_mutex_unlock((pthread_mutex_t *) mutex);

}

然后在等待線程里調用那兩個API:

  • pthread_mutex_lock(&mutex);??

  • pthread_cleanup_push(mutex_clean,?&mutex);??

  • while(global_count<=0)?{??

  • ????pthread_cond_wait(&cond,?&mutex);??

  • }??

  • global_count--;??

  • pthread_cleanup_pop(0);??

  • pthread_mutex_unlock(&mutex); ?

  • 或者一個稍微簡潔一些的寫法:

    ?

  • pthread_mutex_lock(&mutex);??

  • pthread_cleanup_push(mutex_clean,?&mutex);??

  • while(global_count<=0)?{??

  • ????pthread_cond_wait(&cond,?&mutex);??

  • }??

  • global_count--;??

  • pthread_cleanup_pop(1); ?

  • 另外一種解決方案比這個麻煩一些,那就是設置mutex互斥鎖的robust屬性值為PTHREAD_MUTEX_ROBUST;

    對于robust互斥鎖,當持有他的線程沒解鎖就退出以后,別的線程在去調用pthread_mutex_lock,函數會回一個EOWNERDEAD錯誤,線程檢測到這這個錯誤后可以調用pthread_mutex_consistent使robust互斥鎖恢復一致性,緊接著就可以調用phtread_mutex_unlock解鎖了(盡管這個鎖并不是當前這個線程加持的)。解鎖完畢就可以重新調用pthread_mutex_lock了

    采用這種方案的時候,首先要聲明一個全局可見的mutex屬性變量:

    ?

    pthread_mutexattr_mutexattr

    然后初始化并設置屬性值:

    ?

    pthread_mutexattr_init(&mutexaddr);

    pthread_mutexattr_setrobust(&mutexaddr,PTHREEAD_MUTEX_TOBUST);

    有了,mutex屬性,接下來就是在初始化mutex的地方做修改了,通常我門對mutex的初始化都是,pthread_mutex_init(&mutex,NULL);

    現在改成,pthread_mutex_init(&mutex,&mutexaddr);

    ?

    現在準備工作已經完成了,開始干正事了。對于通知線程:

    while(EOWNERDEAD = pthread_mutex_lock(&mutex))

    {

    pthread_mutex_consistent(&mutex);

    pthread_mutex_unlock(&mutex);

    }

    gloable_count++;

    pthread_mutexunlock(&cond);

    pthread_mutex_unlock(&mutex);

    對于等待線程:

    while(EOWNEROEAD == pthread_mutex_lock(&mutex))

    {

    pthread_mutex_consistent(&mutex);

    pthread_mutex_unlock(&mutex);

    }

    while(gloable_count<=0)

    {

    pthread_cond_wait(&cond,&mutex);

    }

    gloable_count--;

    pthread_mutex_unlock(&mutex);

    到這里,所有的事情就完成了。

    ?

    #include <stdio.h>

    #include<pthread.h> //多線程所用頭文件

    #include <semaphore.h> //信號量使用頭文件

    pthread_cond_t g_cond /*=PTHREAD_MUTEX_INITIALIZER*/; //申明條鎖,并用宏進行初始化

    pthread_mutex_t g_mutex ;

    //線程執行函數

    void threadFun1(void)

    {

    int i;

    pthread_mutex_lock(&g_mutex); //1

    pthread_cond_wait(&g_cond,&g_mutex); //如g_cond無信號,則阻塞

    for( i = 0;i < 2; i++ ){

    printf("thread threadFun1.\n");

    sleep(1);

    }

    pthread_cond_signal(&g_cond);

    pthread_mutex_unlock(&g_mutex);

    }

    int main(void)

    {

    pthread_t id1; //線程的標識符

    pthread_t id2;

    pthread_cond_init(&g_cond,NULL); //也可以程序里面初始化

    pthread_mutex_init(&g_mutex,NULL); //互斥變量初始化

    int i,ret;

    ret = pthread_create(&id1,NULL,(void *)threadFun1, NULL);

    if ( ret!=0 ) { //不為0說明線程創建失敗

    printf ("Create pthread1 error!\n");

    exit (1);

    }

    sleep(5); //等待子線程先開始

    pthread_mutex_lock(&g_mutex); //2

    pthread_cond_signal(&g_cond); //給個開始信號,注意這里要先等子線程進入等待狀態在發信號,否則無效

    pthread_mutex_unlock(&g_mutex);

    pthread_join(id1,NULL);

    pthread_cond_destroy(&g_cond); //釋放

    pthread_mutex_destroy(&g_mutex); //釋放

    return 0;

    }

    請大家,先看紅顏色的1,2,明明是1先鎖了互斥變量,但代碼執行到2還是可以鎖定,為什么會這樣?

    pthread_cond_wait()什么情況才會解鎖,繼續跑下去。。。現在看一段典型的應用:看注釋即可。

    問題解釋:當程序進入pthread_cond_wait等待之后,將會把g_mutex進行解鎖,當離開pthread_cond_wait之前,g_mutex會重新加鎖。所以在main中的g_mutex會被加鎖。

    我們還希望對g_count的最大值進行控制,比如希望它的最大值是10;那么當g_count等于10的時候,就要等待。

    ?

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 #include?<stdio.h> #include?<string.h> #include?<stdlib.h> #include?<errno.h> #include?<unistd.h> #include?<pthread.h> #define custom_count?2 #define produce_count?3 int?nNum, nLoop; int?g_count =?0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_MUTEX_INITIALIZER; void?*consume(void?*arg) { ????while?(1) ????{ ????????pthread_mutex_lock(&mutex); ????????while?(g_count ==?0) ????????{ ????????????printf("consume is waiting: %lu\n", pthread_self()); ????????????pthread_cond_wait(&cond, &mutex); ????????} ????????printf("consume is %lu, g_count is %d\n", pthread_self(), g_count); ????????g_count--; ????????pthread_mutex_unlock(&mutex); ????????sleep(1); ????} ????pthread_exit(NULL); } void?*produce(void?*arg) { ????while?(1) ????{ ????????pthread_mutex_lock(&mutex); ????????if?(g_count >=?10) ????????{ ????????????printf("產品太多了,需要休眠1秒\n"); ????????????pthread_mutex_unlock(&mutex); ????????????sleep(1); ????????????continue; ????????} ????????//不需要解鎖再上鎖,大于10,會解鎖,會continue,不會執行下面語句 ????????printf("start produce the product\n"); ????????g_count++; ????????printf("produce is %lu, g_count is %d\n", pthread_self(), g_count); ????????pthread_cond_signal(&cond); ????????pthread_mutex_unlock(&mutex); ????????sleep(1); ????} ????pthread_exit(NULL); } int?main() { ????int?i =?0; ????pthread_t tidCustom[custom_count]; ????pthread_t tidProduce[produce_count]; ????//創建消費者線程 ????for?(i =?0; i < custom_count; i++) ????{ ????????pthread_create(&tidCustom[i], NULL, consume, NULL); ????} ????sleep(3); ????//創建生產者線程 ????for?(i =?0; i < produce_count; i++) ????{ ????????pthread_create(&tidProduce[i], NULL, produce, NULL); ????} ????//等待消費者線程 ????for?(i =?0; i < custom_count; i++) ????{ ????????pthread_join(tidCustom[i], NULL); ????} ????//等待生產者線程 ????for?(i =?0; i < produce_count; i++) ????{ ????????pthread_join(tidProduce[i], NULL); ????} ????printf("parent exit\n"); ????exit(0); }

    再舉個例子:當有兩個變量x,y需要在多線程之間同步并且學生要根據他們的大小來比較啟動不同的縣城執行順序,這邊用到了條件變量的技術:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 <span style="font-family:'KaiTi_GB2312';font-size:18px;"><strong>??? #include?<iostream> ????#include?<pthread.h> ????using?namespace?std; ????pthread_cond_t qready = PTHREAD_COND_INITIALIZER;????//初始構造條件變量 ????pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;????//初始構造鎖 ????pthread_t tid1,tid2,tid3; ????int?x =?10; ????int?y =?20; ????void?*thrd_1(void?*arg) ????{ ????????pthread_mutex_lock(&qlock); ????????while(x<y) ????????{ ????????????pthread_cond_wait(&qready,&qlock); ????????} ????????pthread_mutex_unlock(&qlock); ????????cout<<"1"<<endl; ????????sleep(5); ????} ????void?*thrd_2(void?*arg) ????{ ????????pthread_mutex_lock(&qlock); ????????x =?20; ????????y =?10; ????????cout<<"has change x and y"<<endl; ????????pthread_mutex_unlock(&qlock); ????????if(x > y) ????????{ ????????????pthread_cond_signal(&qready); ????????} ????????cout<<"2"<<endl; ????} ????void?*thrd_3(void?*arg) ????{ ????????pthread_join(tid1,NULL); ????????cout<<"3"<<endl; ????} ????int?main(int?argc,char **argv) ????{ ????????int?err; ????????err = pthread_create(&tid1,NULL,thrd_1,NULL); ????????if(err !=?0) ????????{ ????????????cout<<"pthread 1 create error"<<endl; ????????} ????????err = pthread_create(&tid2,NULL,thrd_2,NULL); ????????if(err !=?0) ????????{ ????????????cout<<"pthread 2 create error"<<endl; ????????} ????????err = pthread_create(&tid3,NULL,thrd_3,NULL); ????????if(err !=?0) ????????{ ????????????cout<<"pthread 3 create error"<<endl; ????????} ????????while(1) ????????{ ????????????sleep(1); ????????} ????????return?0; ????}</strong></span>

    可以看到,創建了3個線程后,執行順序2,1,3,為什么是這個順序?我們接下來來看,當創建tid1線程的識貨,進入線程函數,并且加上了鎖,然后進入pthread_cond_wait函數,這個函數的功能是等等待cond這個變量能夠成功,這個條件是什么?我們稍后再看,現在我們知道,這個函數,在cond條件沒有滿足的時候回卡在這里,并且會吧傳入的互斥鎖解鎖,為什么要解鎖的,你可以想想,如果不解鎖的話,那外部就沒有可以對x,y的修改權,因為其他兩個線程想要修改這兩個值的話都需要對cond進行加鎖。

    好了線程1就是這樣,那之后就會運行線程2,我們看線程2的線程函數,該函數一開始也加了鎖,但當線程1的pthread_cond_wait(&cond,&mutex);解鎖之后,他就可以繼續運行了,并且,在之后,他對x,y,進行了修改,改好之后解鎖,并且調用了pthread_cond_signal(&cond);通知線程1,現在可以知道了吧。這個滿足條件就是要x>y。

    ????現在有個問題,一定是要在發送通知之前進行解鎖嗎?是肯定的,因為如果先發送通知信號給線程1的時候,pthread_cond_wait可能在線程2解鎖之前就返回,而當他返回的時候,會再次將這個鎖鎖定,而這個鎖還沒有在線程2中解鎖,因此會使其在次卡住。雖然這個卡住在線程2運行到解鎖處會消除,但這并不符合我們又是的需求,所以最好實在解鎖之后在發送信號。

    為允許在線程或進程間共享數據,同步通常是必須的。常見的同步方式有:互斥鎖、條件變量、讀寫鎖、信號量。

    另外,對于進程間的同步,也可以通過進程間通信的方式進行同步,包括管道(無名管道、有名管道)、信號量、消息隊列、共享內存、遠程過程調用,當然也可以通過Socket來進行網絡控制。

    ?

    一、互斥鎖和條件變量是同步的基本組成部分。

    ????互斥鎖和條件變量出自POSIX線程標準,多用來同步一個進程中的各個線程。但如果將二者存放在多進程共享的內存區中,它們也可以用來進行進程間的同步。

    ? ?1、互斥鎖用于保護臨界區,以保護任何時刻只有一個線程在執行其中的代碼,其大體輪廓如下:

    ????lock_the_mutex()

    ????臨界區

    ????unlock_the_mutex()

    下列三個函數給一個互斥鎖上鎖和解鎖:

    #inlcude<pthread.h>

    int pthread_mutex_lock(pthread_mutex_t * ptr);//都是不能立刻獲得鎖,將阻塞在此處

    int pthread_mutex_trylock(pthread_mutex_t *ptr);//若是不能立刻獲得鎖,將返回EBUSY,用戶可以根據此返回值做其他操作,非阻塞模式:

    int pthread_mutex_unlock(pthrea_mutex_t *ptr);//釋放鎖

    互斥鎖通常用于保護有多個線程或多個進程分享的共享數據(share data)

    2、條件變量,他是發送信號與等待信號。互斥鎖用戶上鎖,條件變量則用于等待。一般來說,在一個進程/線程進行某種操作,當某種條件成立時,調用pthread_cond_signal()來發送信號,從而使pthread_cond_wait()返回。此處要注意的是,這里所談到的信號,不是系統級別的SIGXXXXXX信號,只是用信號這個詞語更容易理解。條件變量與信號量更接近或者就可以認為是信號量。

    下列兩個函數用來對條件變量進行控制:

    #inculde<pthread.h>

    int pthread_cond_wait(pthread_cond_t *ptr,pthread_mutex_t *mptr);

    int pthread_cond_signal(pthread_cond_t *ptr);

    ????有上述代碼可以看出,條件變量的使用時需要結合所機制的的,繼上面提到的互斥鎖,就是所,一個進程,線程,要等到臨界區的共享數據達到某種狀態時在進行某種操作,而這個狀態成立,則是由另一個進程,線程來完成后發送信號來通知的。

    ????其實想一想,pthread_cond_wait()函數也可以用一個while死循環來等待條件的成立,但是要注意的是,使用while死循環會嚴重消耗cpu,而pthread_cond_wait則是采用線程睡眠的方式,它是一種等待模式,而不是一直的檢查模式。

    ????總的來說,給條件變量發送信號的代碼大體如下:

    pthread_mutex_lock(&mutex);

    設置條件為真

    pthread_mutex_unlock(&mutex);

    pthread_cond_signal(&cond);//發送信號

    等待并進入睡眠以等待條件變為真的代碼如下;

    pthread_mutex_lock(&mutex);

    while(條件為假)

    {

    pthread_cond_wait(&cond,&mutex);

    }

    執行某種操作

    pthread_mutex_unlock(&mutex);

    在這里需要注意的是,pthread_cond_wait(&cond,&mutex)是一個原子操作,當他執行時,首先對mutex解鎖,這樣另外的線程才能得到鎖來修改條件,pthread_cond_wait解鎖后,再將本身的線程進入睡眠,另外,當該函數返回時,會在對mutex進行枷鎖,這樣才能“執行某種操作”后unlock鎖。

    二、讀寫鎖:

    ????顧名思義,讀寫鎖,也是一種所,他是在互斥鎖的基礎上進行了改進,當一個線程獲得寫入鎖時,其他線程任然可以獲得所,只不過獲得的鎖是讀取鎖,因為一個線程寫入,不影響其他進程的操作。

    三、信號量:

    英文:semaphore,他是一種專門用于提供不同線程間,同步手段的源于。

    ?

       進程A ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 進程B

              \          /

         進程    \         /

            ----------------------------------------------------

         內核     \      /

                  信號量


    也就是說,信號量是由內核來維護的,他獨立出進程。因此可以通過它來進行同步。

    ?

    上圖一般來說,是基于Posix有名信號量,可以認為它是系統中的一個特殊文件(因為在Linux中,一切都可以認為是文件),因為在進程間的通信、同步中用的比較多,如果是線程之間的同步,經常用基于Posix內存的信號量。(基于內存的信號量必須在創建時指定是否在進程間共享,有名信號量隨內核有持續性,需手工刪除,而基于內存的信號量具有隨進程的持續性)

      對于信號量的工作原理,其實和互斥鎖+條件變量相似。

      主要函數有:sem_open、sem_close、sem_unlink,這里要注意,close只是關閉信號量,但并未從系統中刪除,而unlink是刪除該信號量。

      sem_wait和sem_trywait函數,他們和pthread_cond_wait功能相似,都是等待某個條件的成立,sem_wait和sem_trywait的區別是,當所指定的信號量的值為0時,后者并不將調用者投入睡眠,而是立刻返回EAGAIN,即重試。

      sem_post和sem_getvalue函數,sem_post將指定的信號量加一,然后喚醒正在等待該信號量值變為正數的任意線程。sem_getvalue是用來獲取當前信號量值的函數。

    ?

    總結:互斥鎖,條件變量,信號量三者的區別:

    (1)互斥鎖必須是又給他上鎖的線程解鎖,信號量沒有這種限制:一個線程等待某個信號量,而另一個線程可以刮出該信號量

    (2)每個信號量有一個與之關聯的值,掛出時+1,等待是-1,那么任何線程都可以掛出一個信號,即使沒有現成在等待該信號的值。不過對于條件變量來說,如果pthread_cond_signal之后沒有任何線程阻塞在pthread_cond_wait()上,那么次條件變量上的信號丟失。

    (3)在各種各樣的同步技巧中,能夠從信號處理程序中安全調用的唯一函數是sem_post

    ?

    轉載于:https://www.cnblogs.com/yjds/p/8598881.html

    總結

    以上是生活随笔為你收集整理的linux C语言多线程库pthread中条件变量的正确用法逐步详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。