スレッド間同期メカニズム----条件変数


一、条件変数の基本原理
条件変数は、スレッドが使用できる別の同期メカニズムです.条件変数は複数のスレッドに1ラウンドの場所を提供する.条件変数は反発量とともに使用され、スレッドが競合することなく特定の条件の発生を待つことができる.条件自体は反発量によって保護される.スレッドは,条件状態を変える前にまず反発量をロックしなければならない.他のスレッドは、条件を計算するには、反発量がロックされた後でなければならないため、反発量を得る前にこの変化に気づかない.
二、条件変数の基本操作
1、条件変数の初期化、破棄
条件変数を使用する前に、次のように条件変数(グローバル変数)を定義する必要があります.
<span style="font-family:Microsoft YaHei;font-size:18px;">pthread_cond_t   condtion;</span>

初期化:pthread_からcond_tデータ型が表す条件変数は2つの方式で初期化でき、定数PTREAD_COND_INITIALIZERは静的割当ての条件変数に割り当てられますが、条件変数が動的割当ての場合はpthread_を使用する必要があります.cond_Init関数は行で初期化されます.
<span style="font-family:Microsoft YaHei;font-size:18px;">#include  <pthread.h>
int  pthread_cond_init(pthread_cond_t  *restrict  cond,  const pthread_condattr_t  *restrict attr);
//   ,  0;  ,      </span>

最初のパラメータcondは、初期化する条件変数を指すポインタです.
2番目のパラメータcond_attrは、初期化する条件変数の特性を定義する属性オブジェクトへのポインタであり、NULLの場合はデフォルトの属性が使用されます.
破棄:
<span style="font-family:Microsoft YaHei;font-size:18px;">#include  <pthread.h>
int  pthread_cond_destory(pthread_cond_t  *cond);
//   ,  0;   ,      </span>

最初のパラメータcondは、破棄する条件変数を指すポインタです.
2、待機条件変数を通知するスレッド
<span style="font-family:Microsoft YaHei;font-size:18px;">#include <pthread.h>
int  pthread_cond_signal(pthread_cond_t  *cond);
int  pthread_cond_broadcast(pthread_cond_t  *cond);
//   ,  0;   ,      。</span>

そのパラメータcondは、通知またはブロードキャストする条件変数を指すポインタである.
(1)pthread_cond_Signal()関数は、条件変数condに関連付けられた条件が現れるのを待つ最初のスレッドを起動するために使用される.condにスレッドがブロックされていない場合、関数は機能しません.condが複数のスレッドをブロックしている場合、スケジューリングポリシーは、ブロックを解除するスレッドを決定します.明らかに、この関数では、現在のスレッドが占有する信号量が暗黙的に解放される.
(2)pthread_cond_broadcast()関数は、条件変数condに関連付けられたすべてのスレッドの出現を待つために起動します.condにスレッドがブロックされていない場合、この関数は機能しません.
3、待機条件変数
(1)pthread_cond_wait()関数は、条件変数を待つのをブロックするために使用されます.
<span style="font-family:Microsoft YaHei;font-size:18px;">#include <pthread.h>
int  pthread_cond_wait(pthread_cond_t   *restrict  cond, pthread_mutex_t  *restrict  mutex);//   ,  0;   ,      。</span>

最初のパラメータcondは、待機する条件変数を指すポインタです.
2番目のパラメータmutexは、条件変数condに関連付けられた反発ロックを指すポインタである.
(2)pthread_cond_timedwait()関数は、指定した時間範囲内で条件変数を待機します.
<span style="font-family:Microsoft YaHei;font-size:18px;">#include <pthread.h>
int  pthread_cond_timedwait(pthread_cond_t  *restrict  cond, pthread_mutex_t   *restrict  mutex,  const  struct  timespec  *restrict  tsptr);
//   ,  0;  ,      。</span>

最初のパラメータcondは、待機する条件変数を指すポインタです.
2番目のパラメータmutexは、条件変数condに関連付けられた反発ロックを指すポインタである.
3番目のパラメータabstimeは、遅延時間を待つ絶対時間であり、この時間範囲内で条件変数関数を取得すると返されます.この時間は1970−1−1:0:0:0からの秒数、すなわち絶対時間である.データ構造は次のように宣言されます.
<span style="font-family:Microsoft YaHei;font-size:18px;">struct  timespec {
        long  ts_sec;
        long  ts_nsec;
};</span>

上記の2つの関数には、スレッドが待機条件変数によって待機状態に入ると、そのリクエストを解放する反発ロックが隠されます.同様に、戻るときは、まずその反発ロックオブジェクトに申請します.
三、条件変数の適用例
1、機能説明
このプログラムは、生産消費の問題を処理するために使用され、一時記憶領域全体が2である.すなわち、任意の時点で、最大2つの製品を一時空間に格納することができ、すでに2つの製品が一時空間に格納されている場合、生産スレッドをブロックする.同様に、一時的なスペースに製品がない場合は、消費スレッドをブロックする必要があることを示します.このプログラムでは、主に生産と消費の2つのスレッドの同期を実現します.
このプログラムでは,反発ロックオブジェクトと条件変数の2つのスレッド間通信メカニズムを用いた.反発ロックは条件変数と連携して動作し、操作手順は以下の通りです.
(1)反発ロックをロックする.
(2)試験条件が満たされているか.
(3)満足したら操作を行い,完了後に反発ロックを解除する.
(4)ステップ2の条件が満たされていない場合は,条件変数メカニズムを用いて待機し,別のスレッドがこの条件を満たす場合はステップ3を実行する.
2、ソースコード分析
<span style="font-family:Microsoft YaHei;font-size:18px;">#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define BUFFER_SIZE 2	//      

struct prodcons			//       
{
	int buffer[BUFFER_SIZE];	//     
	pthread_mutex_t lock;		//   
	int readpos, writepos;		//    
	pthread_cond_t notempty;	//    ,   
	pthread_cond_t notfull;		//    ,   
};

void init(struct prodcons *prod)	//   
{
	pthread_mutex_init(&prod->lock, NULL);//      
	pthread_cond_init(&prod->notempty, NULL);//       
	pthread_cond_init(&prod->notfull, NULL);//       
	prod->readpos = 0;		//        
	prod->writepos = 0;		//        
}

void put(struct prodcons *prod, int data)	//       
{
	pthread_mutex_lock(&prod->lock);	//     
	while((prod->writepos + 1)%BUFFER_SIZE == prod->readpos)
	{						//        
		printf("producer wait for not full
"); pthread_cond_wait(&prod->notfull, &prod->lock);// } prod->buffer[prod->writepos] = data; // prod->writepos++; // 1 if(prod->writepos >= BUFFER_SIZE) // , prod->writepos = 0; pthread_cond_signal(&prod->notempty); // pthread_mutex_unlock(&prod->lock); // } int get(struct prodcons *prod) { int data; pthread_mutex_lock(&prod->lock); // while(prod->writepos == prod->readpos) { // printf("consumer wait for not empty
"); pthread_cond_wait(&prod->notempty, &prod->lock); } // , data = prod->buffer[prod->readpos]; // prod->readpos++; // 1 if(prod->readpos >= BUFFER_SIZE) // , prod->readpos = 0; pthread_cond_signal(&prod->notfull);// pthread_mutex_unlock(&prod->lock); // return data; } #define OVER (-1) struct prodcons buffer; void * producer(void *data) // { int n; for(n = 1; n <= 5; n++) // 5 { printf("producer sleep 1 second .....
"); sleep(1); // 1 printf("put the %d producer
", n); put(&buffer, n); } for(n = 6; n <= 10; n++) // 5 { printf("producer sleep 3 second ......
"); sleep(3); // 3 printf("put the %d product
", n); put(&buffer, n); } put(&buffer, OVER); printf("producer stopped!
"); return NULL; } void * consumer(void *data) // { int d=0; while(1) { printf("consumer sleep 2 second ......
"); sleep(2); // 2 d = get(&buffer); printf("get the %d product
", d); if(d == OVER) break; } printf("consumer stopped!
"); return NULL; } int main(int argc, char *argv[]) { pthread_t th_a, th_b; void * retval; init(&buffer); pthread_create(&th_a, NULL, producer, 0);// pthread_create(&th_b, NULL, consumer, 0);// pthread_join(th_a, &retval); // pthread_join(th_b, &retval); // return 0; } </span>

注意:実装アルゴリズムに問題があり、スレッドの条件変数と反発量の使用に重点を置いています.