1、條件變量node
在線程同步過程當中還有以下的狀況:線程A須要等某個條件成立以後才能繼續往下執行,若是條件不成立,線程A就阻塞,而線程B在執行過程當中使這個條件成立了,就喚醒線程A繼續執行。在Pthread庫中用條件變量阻塞等待一個條件,或者喚醒等待這個條件的線程。條件變量用pthread_cond_t類型的變量來表示。
併發
用pthread_cond_init 初始化條件變量、若是條件變量是靜態分配的,也能夠用宏定義 PTHEAD_COND_INITIALIZER初始化,用pthread_cond_destroy 銷燬條件變量;成功返回0,失敗返回錯誤號。ide
一個條件變量老是和一個Mutex搭配使用的。一個線程能夠調用pthread_cond_wait在一個條件變量上阻塞等待,這個函數作如下三步操做:函數
1. 釋放Mutex高併發
2. 阻塞等待post
3. 當被喚醒時,從新得到Mutex並返回spa
一個線程能夠調用pthread_cond_signal喚醒在某個條件變量上等待的另外一個線程,也能夠調用pthread_cond_broadcast喚醒在這個條件變量上等待的全部線程。線程
2、用生產者-消費者模型來講明對象
顧名思義,能夠看出要實現這個模型,首先得有兩個角色(生產者,消費者),有了兩個角色以外固然該得有一個場合讓兩個都能訪問到的臨界資源(一個場合),還得弄明白生產者與生產者之間的關係(互斥),消費者與消費者之間的關係(互斥),生產者和消費者之間的關係(同步與互斥),總的來講就是一個場所,兩個角色,三種關係。用代碼來實現,生產者生產一個數據,而後發出信號讓,消費者消費,消費者消費完以後給生產者發信號告訴生產者讓生產者繼續生產,如此重複。
隊列
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 }
總結:上面代碼實現的是單生產者和單消費者,生產者-消費者模型,簡單的來講就是要實現生產者與生產者之間互斥,消費者與消費者之間互斥,生產者與消費者之間同步互斥的關係。
3、用信號量實現生產者-消費者模型
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 }
4、讀寫鎖
讀寫鎖實際是一種特殊的自旋鎖,用來處理讀多寫少的狀況,它把對共享資源的訪問者劃分紅讀者和寫者,讀者只對共享資源進行讀訪問,寫者則須要對共享資源進行寫操做。這種鎖相對於自旋鎖而言,能提升併發性,由於在多處理器系統中,它容許同時有多個讀者來訪問共享資源,最大可能的讀者數爲實際的邏輯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 }