Linuxマルチスレッドプログラミング---条件変数
じょうけんへんすう
なぜ条件変数が必要なのか:マルチスレッドプログラミングでは反発ロックのみを使用して反発を完了するのに十分ではありません.例えば、2つのスレッドt 1とt 2があると仮定すると、この2つのスレッドループが1つの共有変数sumを自己増加操作する必要があります.t 1とt 2は反発量を使用するだけで操作が正しく完了することを保証することができます.スレッド実行コードは以下のようになります.
このとき、別のスレッドt 3を追加してcountが100より大きい場合にcount値を0値に再設定する必要がある場合、t 3は以下のように実現することができる.
以上のコードには以下の問題がある:1)sumはほとんどの場合100に達しないが,t 3のコードではelseブランチを歩き,lockとunlockだけを歩き,sleep()を歩くことが多い.これによりCPU処理時間が無駄になる.2)CPU処理時間を節約するために、t 3はsumが100に到達していないことを検出したときにusleep()を一定時間行う.これにより、t 3応答速度の低下というもう一つの問題がもたらされる.sumが200に着いたときにt 3が目が覚めるかもしれません.このように時間と効率に矛盾が生じ,条件変数はこの問題を解決する良い方法である.
1.Pthreads用pthread_cond_t型の変数は条件変数を表す.プログラムはpthread_を使用する必要がありますcond_t変数の前に初期化します.(1)静的初期化静的割当てに対する変数は簡単にPTHREAD_COND_INITIALIZERは、デフォルト動作の条件変数を初期化するために変数に値を付与する. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;(2)動的初期化は動的割当てまたはデフォルト属性を使用しない条件変数に対してpthread_を使用することができる.cond_Init()を初期化します.関数のプロトタイプは次のとおりです:int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);パラメータcondはpthread_を初期化する必要があることを指します.cond_t変数のポインタ、パラメータattrがNULL値を渡す場合、pthread_cond_Init()はcondをデフォルト属性の条件変数に初期化します.関数は正常に0を返します.そうでなければ、0以外のエラーコードが返されます.静的初期化プログラムは通常pthread_を呼び出すよりもcond_Init()はより効果的であり、任意のスレッドが実行を開始する前に、変数が一度実行されることを確認します.
次のコードは、条件変数の初期化の例です.
2.条件変数関数の破棄pthread_cond_destroy()は、そのパラメータが示す条件変数を破棄するために使用され、関数のプロトタイプは以下の通りである:int pthread_cond_destroy(pthread_cond_t *cond);関数は正常に0を返します.そうしないと、0以外のエラーコードが返されます.次のコードでは、条件変数を破棄する方法を示します.
3.待機条件変数と通知条件変数は条件テストとともに使用され、通常、スレッドは条件をテストし、条件が満たさない場合は条件待機関数を呼び出して条件が満たされるのを待つ.条件待ち関数にはpthread_がありますcond_wait()とpthread_cond_timedwait()の2つ、関数のプロトタイプは以下の通りです:int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
pthread_cond_wait()関数は、条件が満たされていない場合に待機し、pthread_cond_timedwait()はしばらく待つだけです.
パラメータcondは条件変数を指すポインタであり、パラメータmutexは反発量を指すポインタであり、スレッドは呼び出す前にこの反発量を持つべきであり、スレッドが条件変数の待機キューに参加すると、待機操作はスレッドにこの反発量を解放させる.pthread_timedwait()の3番目のパラメータabstimeは、戻り時間を指すポインタであり、条件変数通知信号がこの待ち時間の前に現れない場合、待ちはタイムアウトし、abstimeは時間間隔ではなく絶対時間である.以上の関数は正常に0を返すように呼び出されました.そうしないと、pthread_という0以外のエラーコードが返されます.cond_timedwait()関数abstimeが指定した時間が期限切れになった場合、エラーコードはETIMEOUTです.次のコードは、通知が受信され、aがb以上の条件を満たすまでスレッドを待機させる.
4.別のスレッドがパラメータを変更して、条件変数に関連付けられた条件が真になる可能性がある場合、条件変数待機キューに待機している1つ以上のスレッドに通知する必要があります.条件通知関数にはpthread_がありますcond_Signal()とpthread_cond_broadcast()関数、pthread_cond_signal関数は、条件変数でキュー待ちのスレッドを呼び覚ますことができ、pthread_cond_broadcast関数は、条件変数でキュー待ちのスレッドをすべて待機できます.関数のプロトタイプは次のとおりです:int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond); パラメータcondは、条件変数を指すポインタです.関数は正常に0を返します.そうしないと、0以外のエラーコードが返されます.
demo6:
効果のスクリーンショットを実行します.
なぜ条件変数が必要なのか:マルチスレッドプログラミングでは反発ロックのみを使用して反発を完了するのに十分ではありません.例えば、2つのスレッドt 1とt 2があると仮定すると、この2つのスレッドループが1つの共有変数sumを自己増加操作する必要があります.t 1とt 2は反発量を使用するだけで操作が正しく完了することを保証することができます.スレッド実行コードは以下のようになります.
pthread_mutex_t sumlock= PTHREAD_MUTEX_INITIALIZER;
void * t1t2(void)
{
pthread_mutex_lock(&sumlock);
sum++;
pthread_mutex_unlock(&sumlock);
}
このとき、別のスレッドt 3を追加してcountが100より大きい場合にcount値を0値に再設定する必要がある場合、t 3は以下のように実現することができる.
void * t3 (void)
{
pthread_mutex_lock(&sumlock);
if (sum >= 100)
{
sum = 0;
pthread_mutex_unlock(&sumlock);
}
else
{
pthread_mutex_unlock(&sumlock);
usleep(100);
}
}
以上のコードには以下の問題がある:1)sumはほとんどの場合100に達しないが,t 3のコードではelseブランチを歩き,lockとunlockだけを歩き,sleep()を歩くことが多い.これによりCPU処理時間が無駄になる.2)CPU処理時間を節約するために、t 3はsumが100に到達していないことを検出したときにusleep()を一定時間行う.これにより、t 3応答速度の低下というもう一つの問題がもたらされる.sumが200に着いたときにt 3が目が覚めるかもしれません.このように時間と効率に矛盾が生じ,条件変数はこの問題を解決する良い方法である.
1.Pthreads用pthread_cond_t型の変数は条件変数を表す.プログラムはpthread_を使用する必要がありますcond_t変数の前に初期化します.(1)静的初期化静的割当てに対する変数は簡単にPTHREAD_COND_INITIALIZERは、デフォルト動作の条件変数を初期化するために変数に値を付与する. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;(2)動的初期化は動的割当てまたはデフォルト属性を使用しない条件変数に対してpthread_を使用することができる.cond_Init()を初期化します.関数のプロトタイプは次のとおりです:int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);パラメータcondはpthread_を初期化する必要があることを指します.cond_t変数のポインタ、パラメータattrがNULL値を渡す場合、pthread_cond_Init()はcondをデフォルト属性の条件変数に初期化します.関数は正常に0を返します.そうでなければ、0以外のエラーコードが返されます.静的初期化プログラムは通常pthread_を呼び出すよりもcond_Init()はより効果的であり、任意のスレッドが実行を開始する前に、変数が一度実行されることを確認します.
次のコードは、条件変数の初期化の例です.
pthread_cond_t cond;
int error;
if (error = pthread_cond_init(&cond, NULL))
fprintf(stderr, "Failed to initialize cond : %s
", strerror(error));
2.条件変数関数の破棄pthread_cond_destroy()は、そのパラメータが示す条件変数を破棄するために使用され、関数のプロトタイプは以下の通りである:int pthread_cond_destroy(pthread_cond_t *cond);関数は正常に0を返します.そうしないと、0以外のエラーコードが返されます.次のコードでは、条件変数を破棄する方法を示します.
pthread_cond_t cond;
int error;
if (error = pthread_cond_destroy(&cond))
fprintf(stderr, "Failed to destroy cond : %s
", strerror(error));
3.待機条件変数と通知条件変数は条件テストとともに使用され、通常、スレッドは条件をテストし、条件が満たさない場合は条件待機関数を呼び出して条件が満たされるのを待つ.条件待ち関数にはpthread_がありますcond_wait()とpthread_cond_timedwait()の2つ、関数のプロトタイプは以下の通りです:int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
pthread_cond_wait()関数は、条件が満たされていない場合に待機し、pthread_cond_timedwait()はしばらく待つだけです.
パラメータcondは条件変数を指すポインタであり、パラメータmutexは反発量を指すポインタであり、スレッドは呼び出す前にこの反発量を持つべきであり、スレッドが条件変数の待機キューに参加すると、待機操作はスレッドにこの反発量を解放させる.pthread_timedwait()の3番目のパラメータabstimeは、戻り時間を指すポインタであり、条件変数通知信号がこの待ち時間の前に現れない場合、待ちはタイムアウトし、abstimeは時間間隔ではなく絶対時間である.以上の関数は正常に0を返すように呼び出されました.そうしないと、pthread_という0以外のエラーコードが返されます.cond_timedwait()関数abstimeが指定した時間が期限切れになった場合、エラーコードはETIMEOUTです.次のコードは、通知が受信され、aがb以上の条件を満たすまでスレッドを待機させる.
<span style="font-size:18px;">pthread_mutex_lock(&mutex);
while(a < b)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex) ;</span>
4.別のスレッドがパラメータを変更して、条件変数に関連付けられた条件が真になる可能性がある場合、条件変数待機キューに待機している1つ以上のスレッドに通知する必要があります.条件通知関数にはpthread_がありますcond_Signal()とpthread_cond_broadcast()関数、pthread_cond_signal関数は、条件変数でキュー待ちのスレッドを呼び覚ますことができ、pthread_cond_broadcast関数は、条件変数でキュー待ちのスレッドをすべて待機できます.関数のプロトタイプは次のとおりです:int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond); パラメータcondは、条件変数を指すポインタです.関数は正常に0を返します.そうしないと、0以外のエラーコードが返されます.
demo6:
#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
pthread_t tid[3];
int sum = 0;
pthread_mutex_t sumlock = PTHREAD_MUTEX_INITIALIZER;//
pthread_cond_t cond_sum_ready = PTHREAD_COND_INITIALIZER;//
void * t1t2(void *arg)
{
int i;
long id = (long)arg;
for (i = 0; i < 10; i++)
{
pthread_mutex_lock(&sumlock);//
sum++;
printf("t%ld: read sum value = %d
", id + 1 , sum);
pthread_mutex_unlock(&sumlock);
if (sum >= 10)
pthread_cond_signal(&cond_sum_ready);// ,
}
return NULL;
}
void * t3(void *arg)
{
pthread_mutex_lock(&sumlock);
while(sum < 10)
pthread_cond_wait(&cond_sum_ready, &sumlock);//
sum = 0;
printf("t3: clear sum value
");
pthread_mutex_unlock(&sumlock);
return NULL;
}
int main(void)
{
int err;
long i;
for (i = 0; i < 2; i++)
{
//
err = pthread_create(&(tid[i]), NULL, &t1t2, (void *)i);
if (err != 0)
{
printf("Can't create thread :[%s]", strerror(err));
}
}
err = pthread_create(&(tid[2]), NULL, &t3, NULL);
if (err != 0)
printf("Can't create thread :[%s]", strerror(err));
for (i = 0; i < 3; i++)
pthread_join(tid[i], NULL);//
return 0;
}
効果のスクリーンショットを実行します.