2つのスレッドにpthread_cond_wait
を実装しようとしています。私のテストコードは、2つのスレッドを使用して次のシナリオを実行しようとしています。
これまでのところ、コードは「Hello」を5回出力してから、スタックします。私が見た例から、私は正しい方向に進んでいるようです。「ミューテックスをロックし、待って、他のスレッドからシグナルを受け取り、ミューテックスのロックを解除し、何かをし、ループする」
テストコード:
//Import
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
//global variables
pthread_cond_t condA = PTHREAD_COND_INITIALIZER;
pthread_cond_t condB = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *threadA()
{
int i = 0, rValue, loopNum;
while(i<5)
{
//unlock mutex
rValue = pthread_mutex_unlock(&mutex);
//do stuff
for(loopNum = 1; loopNum <= 5; loopNum++)
printf("Hello %d\n", loopNum);
//signal condition of thread b
rValue = pthread_cond_signal(&condB);
//lock mutex
rValue = pthread_mutex_lock(&mutex);
//wait for turn
while( pthread_cond_wait(&condA, &mutex) != 0 )
i++;
}
}
void *threadB()
{
int n = 0, rValue;
while(n<5)
{
//lock mutex
rValue = pthread_mutex_lock(&mutex);
//wait for turn
while( pthread_cond_wait(&condB, &mutex) != 0 )
//unlock mutex
rValue = pthread_mutex_unlock(&mutex);
//do stuff
printf("Goodbye");
//signal condition a
rValue = pthread_cond_signal(&condA);
n++;
}
}
int main(int argc, char *argv[])
{
//create our threads
pthread_t a, b;
pthread_create(&a, NULL, threadA, NULL);
pthread_create(&b, NULL, threadB, NULL);
pthread_join(a, NULL);
pthread_join(b,NULL);
}
正しい方向へのポインタをいただければ幸いです。 (「gcctimeTest.c -o timeTest-lpthread」を使用してLinuxでコンパイルされたコード)
2つの問題があります。 1つ目は、while()
ループを正しく使用していないことです。たとえば、次のようになります。
_//wait for turn
while( pthread_cond_wait(&condA, &mutex) != 0 )
i++;
_
while
ループの本体は、ステートメント_i++
_です。これにより、pthread_cond_wait()
がエラーを返すまで、pthread_cond_wait()
と_i++
_が実行されます。これは本質的に無限ループです。
2つ目は、pthreads条件変数を単独で使用することはできないということです。実際の共有状態とペアにする必要があります(最も単純な場合、この共有状態は、ミューテックスによって保護されたフラグ変数である可能性があります)。 pthread_cond_wait()
関数は、共有状態が特定の値に達するのを待つために使用され、pthread_cond_signal()
関数は、スレッドが共有状態を変更したときに使用されます。このような変数を使用するように例を作り直します。
_//global variables
/* STATE_A = THREAD A runs next, STATE_B = THREAD B runs next */
enum { STATE_A, STATE_B } state = STATE_A;
pthread_cond_t condA = PTHREAD_COND_INITIALIZER;
pthread_cond_t condB = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *threadA()
{
int i = 0, rValue, loopNum;
while(i<5)
{
/* Wait for state A */
pthread_mutex_lock(&mutex);
while (state != STATE_A)
pthread_cond_wait(&condA, &mutex);
pthread_mutex_unlock(&mutex);
//do stuff
for(loopNum = 1; loopNum <= 5; loopNum++)
printf("Hello %d\n", loopNum);
/* Set state to B and wake up thread B */
pthread_mutex_lock(&mutex);
state = STATE_B;
pthread_cond_signal(&condB);
pthread_mutex_unlock(&mutex);
i++;
}
return 0;
}
void *threadB()
{
int n = 0, rValue;
while(n<5)
{
/* Wait for state B */
pthread_mutex_lock(&mutex);
while (state != STATE_B)
pthread_cond_wait(&condB, &mutex);
pthread_mutex_unlock(&mutex);
//do stuff
printf("Goodbye\n");
/* Set state to A and wake up thread A */
pthread_mutex_lock(&mutex);
state = STATE_A;
pthread_cond_signal(&condA);
pthread_mutex_unlock(&mutex);
n++;
}
return 0;
}
_
ここでは、2つの条件変数condA
とcondB
を使用する必要がないことに注意してください。代わりに、1つの条件変数のみを使用した場合、コードは同じように正しくなります。
コードは実際に機能しますほぼ whileループに中括弧を追加すると、私のマシンでは問題ありません。
Cafが言ったことに加えて、threadAがすでにcondB信号を送信した後、threadBが開始されると無限ループに入ります。したがって、whileループで共有状態を使用する必要があるのはなぜですか。
47行目のusleep(1)
を使用して人為的な遅延を導入し、自分の目で確かめることができます。