9

pthread_cond_wait2つのスレッドを実装しようとしています。私のテストコードは、2つのスレッドを使用して、次のシナリオを実行しようとしています。

  • スレッドBは条件を待機します
  • スレッドAは「こんにちは」を5回印刷します
  • スレッドAはスレッドBに信号を送ります
  • スレッドAは待機します
  • スレッドBは「さようなら」を印刷します
  • スレッドBはスレッドAに信号を送ります
  • ループして開始(x5)

これまでのところ、コードは「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でコンパイルされたコード)

4

2 に答える 2

29

2 つの問題があります。1 つ目は、ループを正しく使用していないことですwhile()。たとえば、次のようになります。

//wait for turn
while( pthread_cond_wait(&condA, &mutex) != 0 )

i++;

ループの本体はwhileステートメントです。これは がエラーを返すまでi++実行さpthread_cond_wait()れるため、これは本質的に無限ループです。i++pthread_cond_wait()

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 つの条件変数のみを使用した場合でも、コードは同じように正しくなります。

于 2012-12-03T00:31:34.903 に答える
0

while ループに中かっこを追加すると、コードは実際には私のマシンでほとんど問題なく動作します。

caf の発言に加えて、threadA が既に condB シグナルを送信した後に threadB が開始されると、無限ループに入るでしょう。そのため、while ループで共有状態を使用する必要があるのはなぜですか。

usleep(1)ライン 47を使用して人為的な遅延を導入し、自分の目で確かめることができます。

于 2017-03-25T20:08:44.417 に答える