一、條件變數
在線程同步過程中還有如下的情況:線程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初始化
rrree
-Linable者模型、讀寫鎖的內容,更多相關內容請關注PHP中文網(www.php.cn)!