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

來源:互聯網
上載者:User
一、條件變數
線上程同步過程中還有如下的情況:線程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初始化

1 #include<stdio.h>    2 #include<pthread.h>    3 #define _READNUM_ 2    4 #define _WREITENUM_ 3    5 pthread_rwlock_t lock;    6 int buf=0;    7 void* read(void* reg)    8 {    9     while(1)   10     {   11         if(pthread_rwlock_tryrdlock(&lock) != 0)//讀方式   12         {   13             printf("writer is write! reader wait...\n");   14         }   15         else   16         {   17             printf("reader is reading,val is %d\n",buf);   18             pthread_rwlock_unlock(&lock);   19         }   20         sleep(2);   21     }   22 }   23 void* write(void* reg)   24 {   25     while(1)   26     {   27         if(pthread_rwlock_trywrlock(&lock) != 0)//寫方式   28         {   29             printf("reader is reading ! writer wait...\n");   30             sleep(1);   31         }   32         else   33         {   34             buf++;   35             printf("writer is writing,val is %d\n",buf);   36             pthread_rwlock_unlock(&lock);   37    38         }   39         sleep(1);   40     }   41 }   42 int main()   43 {   44     pthread_rwlock_init(&lock,NULL);   45     pthread_t tid;   46     int i=0;   47     for(i;i< _WREITENUM_;i++)   48     {   49         pthread_create(&tid,NULL,write,NULL);   50     }   51    52     for(i; i< _READNUM_;i++)   53     {   54         pthread_create(&tid,NULL,read,NULL);   55     }   56         pthread_join(tid,NULL);   57         sleep(100);   58         return 0;   59 }

以上就是Linux--Condition Variable(條件變數)實現生產者-消費者模型 、讀寫鎖的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.