Linux -- 条件変数 (条件変数) は、プロデューサー/コンシューマー モデルと読み取り/書き込みロックを実装します。

黄舟
リリース: 2023-03-04 22:32:01
オリジナル
2301 人が閲覧しました

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 }
ログイン後にコピー

4. 読み取り/書き込みロック

読み取り/書き込みロックは実際には特別なスピン ロックであり、より多くの読み取りを処理するために使用されます。この場合、共有リソースへの訪問者はリーダーとライターに分割され、リーダーは共有リソースへの読み取りアクセスのみを持ちますが、ライターは共有リソースに書き込む必要があります。この種類のロックは、スピン ロックと比較して同時実行性を向上させることができます。これは、マルチプロセッサ システムでは、複数のリーダーが同時に共有リソースにアクセスでき、リーダーの最大可能数が実際の論理 CPU 数になるためです。ライターは排他的です。読み取り/書き込みロックは、同時に 1 つのライターまたは複数のリーダーのみを持つことができます (CPU の数に関連します)。ただし、リーダーとライターの両方を同時に持つことはできません。読み取り/書き込みロックは、リーダーとライター (相互に排他的で同期)、リーダーとリーダー (関係なし)、ライターとライター (相互に排他的) 2 つのオブジェクト (リーダーとライター)、1 つの場所の 3 つの関係にも従います。

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(条件変数)を使用するものです。プロデューサーとコンシューマーの実装 リーダー モデルと読み取り/書き込みロックの内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート