首頁  >  文章  >  後端開發  >  Linux--Condition Variable(條件變數)實作生產者-消費者模式 、讀寫鎖

Linux--Condition Variable(條件變數)實作生產者-消費者模式 、讀寫鎖

黄舟
黄舟原創
2017-01-18 10:29:572281瀏覽

一、條件變數
在線程同步過程中還有如下的情況:線程A需要等某個條件成立之後才能繼續往下執行,如果條件不成立,線程A就阻塞,而線程B在執行過程中使這個條件成立了,就喚醒執行緒A繼續執行。在Pthread庫中用條件變數阻塞等待一個條件,或是喚醒等待這個條件的執行緒。條件變數用pthread_cond_t類型的變數來表示。

用pthread_cond_init 初始化條件變數、如果條件變數是靜態分配的,也可以用巨集定義 PTHEAD_COND_INITIALIZER初始化,用pthread_cond_destroy 銷毀條件變數;成功回傳0,失敗回傳錯誤號。
一個條件變數總是和一個Mutex搭配使用的。一個執行緒可以呼叫pthread_cond_wait在一個條件變數上阻塞等待,這個函數做以下三步驟操作:
1.釋放Mutex
2. 阻塞等待
3. 當被喚醒時,重新取得Mutex並回傳
一個執行緒可以呼叫pthread_cond_signal喚醒在某個條件變數上等待的另一個執行緒,也可以呼叫pthread_cond_broadcast喚醒在這個條件變數上等待的所有執行緒。
二、用生產者-消費者模型來說明
顧名思義,可以看出要實現這個模型,首先得有兩個角色(生產者,消費者),有了兩個角色之外當然該得有一個場合讓兩個都能存取的臨界資源(一個場合),也得弄清楚生產者與生產者之間的關係(互斥),消費者與消費者之間的關係(互斥),生產者和消費者之間的關係(同步與互斥),總的來說就是一個場所,兩個角色,三種關係。用程式碼來實現,生產者生產一個數據,然後發出訊號讓,消費者消費,消費者消費完後給生產者發訊號告訴生產者讓生產者繼續生產,如此重複。

1 #include<stdio.h>  
  2 #include <stdlib.h>  
  3 #include<malloc.h>  
  4 #include<pthread.h>                                                                                                                               
  5 #include<semaphore.h>  
  6 typedef int Data_type;  
  7 typedef int* Data_type_p;  
  8 static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;//初始化互斥锁  
  9 static pthread_cond_t needProduct=PTHREAD_COND_INITIALIZER;//初始化条件变量  
 10   
 11  
 12 typedef struct listnode //定义一个链表来存放数据(一个场所)  
 13 {  
 14     Data_type data;  
 15     struct listnode* next;  
 16 }list ,*listp,**listpp;  
 17   
 18 listp head=NULL;  
 19   
 20 static listp buyNode(Data_type _data)  
 21 {  
 22     listp tem=(listp)malloc(sizeof(list));  
 23     if(tem)  
 24     {  
 25         tem -> data=_data;  
 26         tem -> next=NULL;  
 27         return tem;  
 28     }  
 29     return NULL;  
 30 }  
 31 void initList(listpp list)  
 32 {  
 33     *list=buyNode(0);  
 34 }  
 35 void push_list(listp list,Data_type _data)  
 36 {  
 37     listp cur=buyNode(_data);  
 38     listp tem=list;  
 39     while(tem->next)  
 40     {  
 41         tem=tem->next;  
 42     }  
 43     tem ->next=cur;  
 44 }  
 45 void deleteList(listp list)  
 46 {  
 47     if(list)  
 48     {  
 49         free(list);  
 50         list=NULL;  
 51     }  
 52 }  
 53 int pop_list(listp list,Data_type_p data)  
 54 {  
 55     if(list ->next==NULL)  
 56     {  
 57         *data =-1;  
 58         return -1;  
 59     }  
 60     listp tem=list->next;  
 61     list ->next=tem->next;  
 62     *data=tem->data;  
 63     deleteList(tem);  
 64     return 0;  
 65 }  
 66 void PrintList(listp list)  
 67 {  
 68     listp cur=list->next;;  
 69     while(cur)  
 70     {  
 71         printf("%d",cur->data);  
 72         fflush(stdout);  
 73         cur=cur->next;  
 74     }  
 75     printf("\n");  
 76 }  
 77 void *product(void* arg)//定义生产者与生产者之间的关系(互斥)  
 78 {  
 79     int i=0;  
 80     while(1)  
 81     {  
 82         pthread_mutex_lock(&lock);  
 83         printf("product data:%d\n",i);  
 84         push_list(head,i++);  
 85         pthread_mutex_unlock(&lock);  
 86         printf("conduct is ok.weak up comsumer...\n");  
 87         pthread_cond_signal(&needProduct);//当生产者有数据时,发送信号,唤醒消费者  
 88         sleep(2);  
 89     }  
 90   
 91 }  
 92 void *consumer(void* arg)//消费者与消费者之间的关系(互斥)  
 93 {  
 94     Data_type _data;  
 95     while(1)  
 96     {     
 97         pthread_mutex_lock(&lock);  
 98         while(-1==pop_list(head,&_data))  
 99         {  
100             pthread_cond_wait(&needProduct,&lock);//没收到生产者的消息之前就阻塞等待  
101         }  
102         printf("consumer data:%d\n",_data);  
103         pthread_mutex_unlock(&lock);  
104         sleep(1);  
105     }  
106 }  
107 int main()  
108 {  
109     initList(&head);  
110     pthread_t id1;  
111     pthread_t id2;  
112     pthread_create(&id1,NULL,product,NULL);  
113     pthread_create(&id2,NULL,consumer,NULL);  
114     pthread_join(id1,NULL);  
115     pthread_join(id2,NULL);  
116     return 0;  
117 }

總結:上面程式碼實現的是單一生產者和單一消費者,生產者-消費者模型,簡單的來說就是要實現生產者與生產者之間互斥,消費者與消費者之間互斥,生產者與消費者之間同步互斥的關係。

三、用信號量實現生產者-消費者模型
Mutex變數是非0即1的,可看作一種資源的可用數量,初始化時Mutex是1,表示有一個可用資源,
加鎖時獲得此資源,將Mutex減到0,表示不再有可用資源,解鎖時釋放該資源,將Mutex重新加到1,表示又有了一個可用資源。信號量(Semaphore)和Mutex類似,表示可用資源的數量,和Mutex不同的是這個數量可以大於1。即,如果信號量描述的資源數目是1時,此時的信號量和互斥鎖相同!
sem_init()初始化信號量

sem_wait()P操作獲得資源

sem_post()V操作釋放資源

sem_destroy()銷毀信號量

上面是用表鏈寫的生產者-消費者鏈數是動態分配的,現在基於固定大小的環形隊列重寫生產者-消費者模型

1 #include<stdio.h>  
  2 #include<pthread.h>  
  3 #include<semaphore.h>  
  4 #define PRODUCT_SIZE 20  
  5 #define CONSUMER_SIZE 0  
  6   
  7 sem_t produceSem;  
  8 sem_t consumerSem;  
  9 int Blank [PRODUCT_SIZE];  
 10   
 11 void* product(void* arg)  
 12 {  
 13     int p=0;  
 14     while(1)  
 15     {  
 16         sem_wait(&produceSem); //申请资源。  
 17         int _product=rand()%100;  
 18         Blank[p]=_product;  
 19         printf("product is ok ,value is :%d\n",_product);  
 20         sem_post(&consumerSem);//释放资源  
 21         p=(p+1) % PRODUCT_SIZE;  
 22         sleep(rand()%3);  
 23     }  
 24   
 25 }  
 26 void* consumer(void* arg)  
 27 {  
 28     int p=0;  
 29     while(1)  
 30     {  
 31         sem_wait(&consumerSem);//申请资源  
 32         int _consumer=Blank[p];  
 33         printf("consumer is ok,value is :%d\n",_consumer);  
 34         sem_post(&produceSem);//释放资源  
 35         p=(p+1)% PRODUCT_SIZE;  
 36         sleep(rand()%5);  
 37     }  
 38 }  
 39 int main()  
 40 {   sem_init(&produceSem,0,PRODUCT_SIZE);  
 41     sem_init(&consumerSem,0,CONSUMER_SIZE);  
 42     pthread_t tid1,tid2;  
 43     pthread_create(&tid1,NULL,product,NULL);  
 44     pthread_create(&tid2,NULL,consumer,NULL);  
 45     pthread_join(tid1,NULL);  
 46     pthread_join(tid2,NULL);  
 47     sem_destroy(&produceSem);  
 48     sem_destroy(&consumerSem);  
 49     return 0;  
 50 }

四、讀寫鎖 
讀寫鎖實際上是一種特殊的自旋鎖,用來處理讀多寫少的情況,它將對共享資源的訪客劃分成讀者和寫者,讀者只對共享資源進行讀取訪問,寫者則需要對共享資源進行寫入操作。這種鎖相對於自旋鎖而言,能提高並發性,因為在多處理器系統中,它允許同時有多個讀者來存取共享資源,最大可能的讀者數為實際的邏輯CPU數。寫者是排他性的,一個讀寫鎖同時只能有一個寫者或多個讀者(與CPU數相關),但不能同時既有讀者又有寫者。讀寫鎖也遵循3種關係:讀者-寫者(互斥與同步)、讀者-讀者(無關係)、寫者-寫者(互斥)2個對象(讀者和寫者),1個場所。
pthread_rwlock_wrlock 寫方式,成功回傳0,失敗回傳錯誤碼

pthread_rwlock_rdlock 讀取方式,成功回傳0,失敗回傳錯誤碼

pthread_rwlock_init初始化

rrrree

pthread_rwlock_init初始化

rrree
-Linable者模型、讀寫鎖的內容,更多相關內容請關注PHP中文網(www.php.cn)!

🎜🎜🎜
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:Linux--訊號下一篇:Linux--訊號