1. 条件変数
スレッド同期のプロセスでは、次の状況も発生します: スレッド A は、実行を続行する前に、特定の条件が確立されるまで待機する必要があります。条件が確立されていない場合、スレッド A はブロックされます。スレッド B は実行中にこれを使用します。条件が成立すると、スレッド A が起動されて実行を継続します。 Pthread ライブラリの条件変数を使用して、条件の待機をブロックしたり、この条件を待機しているスレッドをウェイクアップしたりできます。条件変数は、pthread_cond_t 型の変数で表されます。
条件変数が静的に割り当てられている場合は、pthread_cond_init を使用して条件変数を初期化し、pthread_cond_destroy を使用して条件変数を破棄し、成功した場合は 0 を返し、失敗した場合はエラー番号を返すこともできます。
条件変数は常にミューテックスとともに使用されます。スレッドは pthread_cond_wait を呼び出してブロックし、条件変数を待機します。
1. ミューテックスを解放します
2. ブロックして待機します
3. スレッドが呼び出すことができます。 pthread_cond_signal 特定の条件変数を待機している別のスレッドを起動するには、pthread_cond_broadcast を呼び出して、この条件変数を待機しているすべてのスレッドを起動することもできます。
2 番目に、プロデューサー/コンシューマー モデルを使用して説明します
名前が示すように、このモデルを実装するには、最初に 2 つの役割 (プロデューサー、コンシューマー) が必要であることがわかります。もちろん、この 2 つの役割も必要です。重要なリソースに(一度に)双方がアクセスできるようにするには、生産者と生産者の関係(相互排他)、消費者と消費者の関係(相互排他)、生産者と消費者の関係も理解する必要があります。プロデューサー間の関係 (同期と相互排他) は、通常、1 つの場所、2 つの役割、および 3 つの関係です。コードで実装するには、プロデューサーがデータを生成し、それを消費するようにコンシューマーにシグナルを送信し、プロデューサーに生産を続行するようシグナルを送信します。
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 になり、利用可能なリソースがあることを示します。ロック時に取得 このリソースのミューテックスを 0 に減らして、利用可能なリソースがなくなったことを示します。ロックを解除するときにリソースを解放し、別の利用可能なリソースがあることを示すミューテックスを 1 に戻します。セマフォは 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 }
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 }