スレッド内の条件変数pthread_cond_wait、pthread_cond_signal

4991 ワード

じょうけんへんすう
条件変数はスレッド間で共有されるグローバル変数を利用して同期するメカニズムであり、主に2つの動作を含む:1つのスレッドは「条件変数の条件が成立する」のを待って保留する;別のスレッドは「条件成立」(条件成立信号を与える)を使用します.競合を防止するために、条件変数の使用は常に反発ロックと結合されます.
1.条件変数の作成とログアウトは、相互反発ロックと同様に、PTHREAD_を使用する静的動的2つの作成方法があります.COND_INITIALIZER定数、以下の通り:pthread_cond_t   cond=PTHREAD_COND_INITIALIZER  
動的呼び出しpthread_cond_Init()関数、API定義:int pthread_cond_init(pthread_cond_t   *cond,   pthread_condattr_t   *cond_attr)  
POSIX規格では条件変数の属性が定義されているが、LinuxThreadsでは実装されていないためcond_attr値は通常NULLであり、無視される.
条件変数をログアウトするにはpthread_を呼び出す必要があります.cond_destroy()は、スレッドがこの条件変数で待機していない場合にのみ、この条件変数をログアウトできます.そうしないと、EBUSYに戻ります.Linuxが実装する条件変数にはリソースが割り当てられていないため、ログアウト動作には待機スレッドがあるかどうかを確認するだけが含まれます.API定義は、int pthread_cond_destroy(pthread_cond_t   *cond)  
 
2.待機と励起
int   pthread_cond_wait(pthread_cond_t   *cond,   pthread_mutex_t   *mutex)  int   pthread_cond_timedwait(pthread_cond_t   *cond,   pthread_mutex_t   *mutex,   const   struct   timespec   *abstime)  
待機条件には2つの方法があります.無条件待機pthread_cond_wait()とタイミング待ちpthread_cond_timedwait()は、タイマ待ち方式が所定の時刻までに条件が満たされなければETIMEOUTに戻り、待機を終了し、abstime()システム呼び出しと同じ意味の絶対時間形式で現れ、0はグリニッジ時間1970年1月1日0時0分0秒を示す.
いずれの待機方式でも、pthread_が複数のスレッドで同時に要求されることを防止するために、1つの反発ロックと組み合わなければならない.cond_wait()(またはpthread_cond_timedwait()、以下同)の競合条件(Race Condition).mutex反発ロックは通常ロック(PTHREAD_MUTEX_TIMED_NP)または適応ロック(PTHREAD_MUTEX_ADAPTIVE_NP)でなければならず、pthread_cond_wait()を呼び出す前に本スレッドによってロック(pthread_mutex_lock()されなければならず、更新条件待ちキューの前にmutexはロック状態が維持され、スレッドが保留中に入る前にロックを解除します.条件が満たされてpthread_を離れるcond_wait()の前にmutexはpthread_に入るために再ロックされます.cond_wait()前のロック動作に対応します.
励起条件には2つの形態があり,pthread_cond_Signal()は、この条件を待つスレッドをアクティブにし、複数の待機スレッドが存在する場合、エンキュー順にそのうちの1つをアクティブにします.pthread_cond_broadcast()は、すべての待機スレッドをアクティブにします.
 
3.その他
pthread_cond_wait()とpthread_cond_timedwait()はいずれもキャンセルポイントとして実装されるため、ここで待機しているスレッドは直ちに再実行され、mutexを再ロックした後pthread_を離れるcond_wait()を実行し、キャンセル動作を実行します.つまりpthread_cond_wait()はキャンセルされ、mutexはロック状態を維持するため、コールバック関数を終了してロックを解除することを定義する必要があります.
次の例では、反発ロックと条件変数の組み合わせの使用、および条件待機動作への影響の取り消しについて説明します.例では、2つのスレッドが起動され、同じ条件変数が待機しているが、終了コールバック関数(例の注釈セクションを参照)を使用しない場合、tid 2はpthread_mutex_lock()で永続的に待機する.コールバック関数を使用するとtid 2の条件待ちとメインスレッドの条件励起が正常に動作します.
#include   <stdio.h> 
#include   <pthread.h> 
#include   <unistd.h> 

pthread_mutex_t   mutex; 
pthread_cond_t     cond; 

void   *   child1(void   *arg) 
{ 
                pthread_cleanup_push(pthread_mutex_unlock,&mutex); /*   comment   1   */ 
                while(1){ 
                        printf( "thread   1   get   running   /n "); 
                        printf( "thread   1   pthread_mutex_lock   returns   %d/n ", 
                        pthread_mutex_lock(&mutex)); 
                        pthread_cond_wait(&cond,&mutex); 
                        printf( "thread   1   condition   applied/n "); 
                        pthread_mutex_unlock(&mutex); 
                        sleep(5); 
                } 
                pthread_cleanup_pop(0);/*   comment   2   */ 
} 

void   *child2(void   *arg) 
{ 
                while(1){ 
                        sleep(3);  /*   comment   3   */ 
                        printf( "thread   2   get   running./n "); 
                        printf( "thread   2   pthread_mutex_lock   returns   %d/n ", 
                        pthread_mutex_lock(&mutex)); 
                        pthread_cond_wait(&cond,&mutex); 
                        printf( "thread   2   condition   applied/n "); 
                        pthread_mutex_unlock(&mutex); 
                        sleep(1); 
                } 
} 


int   main(void) 
{ 
                int   tid1,tid2; 
                printf( "hello,   condition   variable   test/n "); 
                pthread_mutex_init(&mutex,NULL); 
                pthread_cond_init(&cond,NULL); 
                pthread_create(&tid1,NULL,child1,NULL); 
                pthread_create(&tid2,NULL,child2,NULL); 
                do{ 
                        sleep(2);/*   comment   4   */ 
                        pthread_cancel(tid1);/*   comment   5   */ 
                        sleep(2);            /*   comment   6   */ 
                        pthread_cond_signal(&cond); 
                } while(1);    
 
                sleep(100); 
                pthread_exit(0); 
}   

コメント5のpthread_をしないとcancel()動作は、sleep()遅延操作がなくてもchild 1とchild 2が正常に動作します.注釈3および注釈4の遅延により、child 1はキャンセル動作を完了する時間があり、child 2がchild 1が終了した後にリクエストロック操作に入ることができる.アノテーション1とアノテーション2のコールバック関数定義がない場合、child 2がロックを要求する場所にシステムが停止します.一方、コメント3とコメント4の遅延を同時に行わなければ、child 2は、child 1がキャンセル動作を完了する前に制御され、申請ロックの操作を円滑に実行することができるが、pthread_cond_wait()には、mutexを申請する操作もあるので.child 1関数は標準的な条件変数の使用方法を示します:コールバック関数保護、待機条件前ロック、pthread_cond_wait()が戻ったらロックを解除します.
条件変数メカニズムは非同期信号セキュリティではなく、すなわち、信号処理関数でpthread_を呼び出すcond_Signal()またはpthread_cond_broadcast()はデッドロックを引き起こす可能性が高い