linux網絡編程之posix 線程(四):posix 條件變量與互斥鎖 示例生產者--消費者問題

http://blog.csdn.net/jnu_simba/article/details/9129939

一、posix 條件變量

一種線程間同步的情形:線程A需要等某個條件成立才能繼續往下執行,現在這個條件不成立,線程A就阻塞等待,而線程B在執行過程中使這個條件成立了,就喚醒線程A繼續執行。


在pthread庫中通過條件變量(Condition Variable)來阻塞等待一個條件,或者喚醒等待這個條件的線程。Condition Variable用pthread_cond_t類型的變量表示,和Mutex的初始化和銷毀類似,pthread_cond_init函數初始化一個Condition Variable,attr參數為NULL則表示缺省屬性,pthread_cond_destroy函數銷毀一個Condition Variable。如果ConditionVariable是靜態分配的,也可以用宏定義PTHEAD_COND_INITIALIZER初始化,相當于用pthread_cond_init函數初始化并且attr參數為NULL。


一個Condition Variable總是和一個Mutex搭配使用的。一個線程可以調用pthread_cond_wait在一個Condition Variable上阻塞等待,這個函數做以下三步操作:
1. 釋放Mutex
2. 阻塞等待
3. 當被喚醒時,重新獲得Mutex并返回

注意:3個操作是原子性的操作,之所以一開始要釋放Mutex,是因為需要讓其他線程進入臨界區去更改條件,或者也有其他線程需要進入臨界區等待條件。


一個線程可以調用 pthread_cond_signal 喚醒在某個Condition Variable上等待的第一個線程,也可以調用 pthread_cond_broadcast 喚醒在這個Condition Variable上等待的所有線程。


上面的函數具體可以man 一下。


二、條件變量使用規范

(一)、等待條件代碼
pthread_mutex_lock(&mutex);

while (條件為假)

pthread_cond_wait(cond, mutex);

修改條件
pthread_mutex_unlock(&mutex);


(二)、給條件發送通知代碼
pthread_mutex_lock(&mutex);
設置條件為真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);


假設第一段用于消費者線程,第二段用于生產者線程。為什么消費者線程要用while 而不是if 就可以呢?在man pthread_cond_wait 有一句:If a signal is delivered to a thread waiting for a condition variable, upon return from the signal handler the thread resumes waiting for the condition variable as if it was not interrupted, or it shall return zero due to spurious wakeup.

即是說如果正在等待條件變量的一個線程收到一個信號,從信號處理函數返回的時候線程應該重新等待條件變量就好象沒有被中斷一樣,或者被虛假地喚醒返回0。如果是上述情形,那么其實條件并未被改變,那么此時如果沒有繼續判斷一下條件的真假就繼續向下執行的話,修改條件將會出現問題,所以需要使用while 循環再判斷一下,如果條件還是為假必須繼續等待。

注:在多處理器系統中,pthread_cond_signal 可能會喚醒多個等待條件的線程,這也是一種spurious wakeup。


當生產者線程較多,即生產得比較快,在這邊假設是無界的緩沖區(比如鏈表),可以不停地生產,使用pthread_cond_signal ?發出通知的時候,如果此時沒有消費者線程在等待條件,那么這個通知將被丟棄,但也不影響整體代碼的執行,沒有消費者線程在等待,說明產品資源充足,即while 判斷失敗,不會進入等待狀態,直接消費產品(即修改條件)。


三、生產者消費者問題?

C++ Code?
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
90
91
#include?<unistd.h>
#include?<sys/types.h>
#include?<pthread.h>
#include?<semaphore.h>

#include?<stdlib.h>
#include?<stdio.h>
#include?<errno.h>
#include?<string.h>

#define?ERR_EXIT(m)?\
????????do?\
????????{?\
????????????????perror(m);?\
????????????????exit(EXIT_FAILURE);?\
????????}?while(0)

#define?CONSUMERS_COUNT?2
#define?PRODUCERS_COUNT?1

pthread_mutex_t?g_mutex;
pthread_cond_t?g_cond;

pthread_t?g_thread[CONSUMERS_COUNT?+?PRODUCERS_COUNT];

int?nready?=?0;

void?*consume(void?*arg)
{
????int?num?=?(int)arg;
????while?(1)
????{
????????pthread_mutex_lock(&g_mutex);
????????while?(nready?==?0)
????????{
????????????printf("%d?begin?wait?a?condtion?...\n",?num);
????????????pthread_cond_wait(&g_cond,?&g_mutex);
????????}

????????printf("%d?end?wait?a?condtion?...\n",?num);
????????printf("%d?begin?consume?product?...\n",?num);
????????--nready;
????????printf("%d?end?consume?product?...\n",?num);
????????pthread_mutex_unlock(&g_mutex);
????????sleep(1);
????}
????return?NULL;
}

void?*produce(void?*arg)
{
????int?num?=?(int)arg;
????while?(1)
????{
????????pthread_mutex_lock(&g_mutex);
????????printf("%d?begin?produce?product?...\n",?num);
????????++nready;
????????printf("%d?end?produce?product?...\n",?num);
????????pthread_cond_signal(&g_cond);
????????printf("%d?signal?...\n",?num);
????????pthread_mutex_unlock(&g_mutex);
????????sleep(1);
????}
????return?NULL;
}

int?main(void)
{
????int?i;

????pthread_mutex_init(&g_mutex,?NULL);
????pthread_cond_init(&g_cond,?NULL);


????for?(i?=?0;?i?<?CONSUMERS_COUNT;?i++)
????????pthread_create(&g_thread[i],?NULL,?consume,?(void?*)i);

????sleep(1);

????for?(i?=?0;?i?<?PRODUCERS_COUNT;?i++)
????????pthread_create(&g_thread[CONSUMERS_COUNT?+?i],?NULL,?produce,?(void?*)i);

????for?(i?=?0;?i?<?CONSUMERS_COUNT?+?PRODUCERS_COUNT;?i++)
????????pthread_join(g_thread[i],?NULL);

????pthread_mutex_destroy(&g_mutex);
????pthread_cond_destroy(&g_cond);

????return?0;
}


在上面程序中,++nready 就當作是生產產品了,--nready就當作是消費產品了,跟前面文章所不同的是,這里沒有緩沖區大小的概念,可以當作是無界緩沖區,生產者可以一直生產,但消費者只有當有產品的時候才能消費,否則就得等待,等待結束的條件就是nready > 0;上面也說過當生產得比較快(生產者線程多)的時候,也有可能消費者線程一直不存在等待的狀態,因為nready 的值很大,即產品資源很多。現在設置的是2個消費者線程和1個生產者線程,所以動態輸出來看一般是2個消費者線程輪流等待。


參考:

《linux c 編程一站式學習》

《UNP》


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383916.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383916.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383916.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

3-V2-類和對象 -- const內聯 靜態成員 友元

const修飾成員函數 在成員函數后面加一個const, const修飾this指針指向的對象, 保證調用這個const成員函數的對象在函數內不會被改變 注意:成員函數如果不修改成員變量,則加上const,成員函數如果要修改成員變量,此時就不能給其加上const修飾了 1.const對象不能調用非const…

C語言 二級指針內存模型混合實戰

http://www.cnblogs.com/zhanggaofeng/p/5485833.html //二級指針內存模型混合實戰 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h>//將內存模型①和內存模型②的數據拷貝到內存模型③ char ** threemodel(ch…

擴展歐幾里得算法

對于a?xb?yca*xb*yca?xb?yc,這樣一個二元一次方程組&#xff0c;我們想要得到他的一組解可以用擴展歐幾里得算法&#xff0c;參數列表的a,b,x,y就是方程中的a,b,x,y&#xff0c;d計算出來是gcd(a,b)。 算法求出來的是a?xb?ygcd(a,ba*xb*ygcd(a,ba?xb?ygcd(a,b的一組解…

Linux 網絡編程八(epoll應用--大并發處理)

http://www.cnblogs.com/zhanggaofeng/p/5901316.html //頭文件 pub.h #ifndef _vsucess#define _vsucess#ifdef __cplusplus extern "C" {#endif //服務器創建socket int server_socket(int port);//設置非阻塞 int setnonblock(int st);//接收客戶端socket int ser…

約瑟夫問題

n個人編號為0…n-1圍成一個圈,從0開始報數,每經過k個人那個人就退出這個圈不再報數,問最后留下來的人的編號. 樸素的做法當然是模擬,但是n,k的值一旦變得比較大的時候就難以解決問題. 我們考慮歸納的解決問題 當只有一個人的時候答案顯然為0, 假設我們已知n-1個人的時候答案為…

【數據結構與算法】內部排序之三:堆排序(含完整源碼)

轉載請注明出處&#xff1a;http://blog.csdn.net/ns_code/article/details/20227303 前言 堆排序、快速排序、歸并排序&#xff08;下篇會寫這兩種排序算法&#xff09;的平均時間復雜度都為O&#xff08;n*logn&#xff09;。要弄清楚堆排序&#xff0c;就要先了解下二叉堆這…

模線性方程(中國剩余定理+擴展中國剩余定理)

已知一系列除數和模數,求最小的滿足條件的數 我們先考慮一般的情況&#xff0c;即模數不互質。&#xff08;擴展中國剩余定理&#xff09; 我們考慮兩個方程的情況 x%MR xk1?MRxk1 * MRxk1?MR x%mr xk2?mrxk2 * mrxk2?mr 所以k1?MRk2?mrk1 * MRk2 * mrk1?MRk2?mr 即…

C++:Vector和List的實現

Vector的實現 //test.h #pragma once#include <iostream> #include <cstdio> #include <string.h> #include <assert.h>using namespace std;typedef int DataType;#define TESTHEADER printf("\n%s\n", __FUNCTION__)class Vector { publi…

【數據結構】(面試題)使用兩個棧實現一個隊列(詳細介紹)

http://blog.csdn.net/hanjing_1995/article/details/51539578 使用兩個棧實現一個隊列 思路一&#xff1a; 我們設定s1是入棧的&#xff0c;s2是出棧的。 入隊列&#xff0c;直接壓到s1即可 出隊列&#xff0c;先把s1中的元素倒入到s2中&#xff0c;彈出s2中的棧頂元素&#x…

POJ 1006 Biorhythms

中國剩余定理的模板題 只是有一個問題就是求出來Xk*MR中的R比給定的日期還大&#xff0c;但是如果負數的整除就不是向下取整了&#xff0c;為了解決這個問題&#xff0c;我們將R減小M&#xff0c;這樣總是正的&#xff0c;求出來的就沒有什么問題。 #include <iostream>…

POJ 3696 歐拉函數+快速冪

題目的意思大概就是問是否存在一串全是8的數字是L的倍數 直接想沒有什么想法&#xff0c;要想到用簡潔的形式將這個數字表示出來&#xff0c;對于每一位都是8的數字我們可以用 X8*(10k-1)/9的形式表示出來&#xff0c;那么題目的意思就是求X使L|X&#xff0c;我們先處理一下8和…

兩個棧實現一個隊列,兩個隊列實現一個棧

http://blog.csdn.net/zw_1510/article/details/51927554 問題1&#xff1a;用兩個棧實現一個隊列&#xff0c;實現隊列的push和delete操作 棧的特性是先進后出&#xff08;FILO&#xff09;,隊列的特性是先進先出&#xff08;FIFO&#xff09;,在實現delete時&#xff0c;我們…

C++:String的寫時拷貝

String的寫時拷貝 //test.h #pragma once#include <iostream> #include <string.h> #include <cstdio> #include <assert.h> using namespace std;#define TESTHEADER printf("\n%s\n", __FUNCTION__) class String { public:String(const …

兩個棧實現一個隊列與兩個隊列實現一個棧

http://blog.csdn.net/z84616995z/article/details/19204529 兩個棧實現一個隊列&#xff1a; 原理方法&#xff1a;用一個棧為主棧&#xff0c;一個棧為輔助棧存放臨時元素。 入隊&#xff1a;將元素依次壓入主棧 出隊&#xff1a;先檢測輔助棧是否為空&#xff0c;如果非空&a…

UVa11426——歐拉函數

發現對于gcd問題要多和歐拉函數聯系在一起&#xff0c;雖然有時候并不是互質&#xff0c;但是我們知道有多少互質的然后根據互質的數目就能解決很多個gcd的問題 對于這道題目&#xff0c;題目要求的是所有數對的gcd的和&#xff0c;直接思考的話有難度。但是我們如果聯想到歐拉…

C++:繼承和多態

虛函數:只有類的成員函數才能定義為虛函數 虛函數 在類的成員函數前面加上一個 virtual 關鍵字, 此時這個成員函數就叫做虛函數 虛函數 當在子類中定義了一個與父類完全相同的虛函數的時候,此時就叫做子類的虛函數重寫了父類的虛函數 構成多態的條件 派生類重寫基類的虛函數…

POJ 1061擴展歐幾里得

擴展歐幾里得的模板題&#xff0c;需要注意的是為了得到一個最小正數解我們要使axbyc中的a,b都是正數 #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include<cmath> #include<ctim…

C++::探索對象模型

前面我們已經知道, 在沒有虛函數的時候, 對象的大小就是對應的成員變量的大小, 而成員函數不會占用對象的空間, 今天我們來討論一下, 當類中定義了虛函數的時候, 此時對象的大小以及對象模型 非繼承下的對象模型 class Base { public:virtual void func1(){cout << &qu…

auto_ptr

#include <iostream> #include <memory> using namespace std;class A { public:A(){cout<<"構造"<<endl;}~A(){cout<<"A析構"<<endl;}void fun(){cout<<"A::fun"<<endl;} };class PA { public…

POJ 2142——擴展歐幾里得

題目是很裸的擴展歐幾里得&#xff0c;但是對x,y有限制條件&#xff0c;要求所有x,y中abs(x)abs(y)最小&#xff0c;在這個條件下要求abs(a* x)abs(b* y)最小 顯然我們需要用擴展歐幾里得求得一組解&#xff0c;問題在于如何處理這組解以得到符合條件的值。 我是這樣處理的&a…