6

現在、条件変数を使用して 2 つのスレッド (pthreads) を同期させていますが、予期しない動作が発生しています。スレッドが既に条件を待機していることを確認したにもかかわらず、別のスレッドが条件を通知しても復帰しません。

これをデスクトップ環境で実行したことは注目に値するかもしれませんが、これは期待どおりに実行されますが、この問題は、ulibc を使用して組み込み環境でプログラムを実行したときに発生します。

トラブルシューティングを行うために、コードを削除して、ロック/ロック解除/シグナリングを実行する 2 つのスレッドだけにしました。これを次に示します。

#include <stdio.h>
#include <pthread.h>
#include <stdbool.h>

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t condition2 = PTHREAD_COND_INITIALIZER;
bool predicate1 = false;
bool predicate2 = false;

static void * ThreadFunc2(void * arg) {
    sleep(1);    // For testing purposes, ensures this thread is run after Thread1

    pthread_mutex_lock(&mutex2);
    while(1) {
        pthread_mutex_lock(&mutex1);
        // Do some work - Eg receive some data from a socket
        predicate1 = false;
        pthread_cond_signal(&condition1);
        pthread_mutex_unlock(&mutex1);

        predicate2 = true;
        while(predicate2 == true)
            pthread_cond_wait(&condition2, &mutex2);

        // Do some more work - Eg send response data to socket
    }
}

static void * ThreadFunc1(void * arg) {
    int result;

    pthread_mutex_lock(&mutex1); 
    while(1) {
        predicate1 = true;
        while(predicate1 == true)
            pthread_cond_wait(&condition1, &mutex1);

        // Do some work - Eg process data on the socket and prepare response data to be sent
        pthread_mutex_lock(&mutex2);
        predicate2 = false;
        pthread_cond_signal(&condition2);
        pthread_mutex_unlock(&mutex2);
    }
}

int main(int argc, char * argv[]) {
    pthread_t thread1Id, thread2Id;

    pthread_create(&thread1Id, NULL, ThreadFunc1, NULL);
    pthread_create(&thread2Id, NULL, ThreadFunc2, NULL);

    while(1) {
        sleep(1);
    }

    return 0;
}

ミューテックス 2/条件 2/述語 2 に関連するすべてのステートメントを除外すると、2 つのスレッドは期待どおりに連携します。

上記のコードでは、しばらくすると (すべての作業が取り除かれるため、各ループが非常に高速に実行されます)、Threadfunc1 の条件 1 の待機は、アプリケーションの停止につながる Threadfunc2 によって通知されても、起きません。

また、デバッグを支援するために、実際の pthread_* 関数を呼び出す前に、一致する行番号で標準出力にメッセージを出力するように pthread_* 関数を再定義しました。これにより、各 pthread 操作の流れをたどり、シグナルがすでに待機状態に送信されていることを確認できました。

上記の実装に存在する可能性のある潜在的な問題に光を当てるのを手伝ってくれる人はいますか?

ご提案いただきありがとうございます。

4

3 に答える 3

2

あなたの間違いは、pthread_cond_wait() の呼び出し後に条件変数によって使用されるミューテックスをロック解除していないことです。

たとえば、pthread_cond_wait() は、スレッドがブロックされている間、ミューテックスを内部的にロック解除しますが、ウェイクアップするとロックを再取得し、明示的に解放する必要があります。

cond の詳細については、このチュートリアルを参照してください。変数: https://computing.llnl.gov/tutorials/pthreads/#ConditionVariables

于 2013-05-27T05:55:21.773 に答える
1

解決策-以下の説明を参照
してください

...
pthread_mutex_lock(&mutex1);
predicate1 = false;
pthread_mutex_unlock(&mutex1);
pthread_cond_signal(&condition1);
...

関数 ThreadFunc2 で、同様にスレッド 1 で

...
pthread_mutex_lock(&mutex2);
predicate2 = true;
pthread_mutex_unlock(&mutex2);
pthread_cond_signal(&condition2);
...

関数 ThreadFunc1 で。

説明プログラム スレッド 2 で、シグナリング呼び出しに入ります

pthread_cond_signal(&condition1); //  thread 2 with mutex1 locked

mutex1 がロックされています。スレッド 1 はブロッキングからのみ離れることができます

pthread_cond_wait(&mutex1);       //  thread 1 leaves only after mutex1 unlocked

これは、この関数呼び出しの保証された動作です。つまり、続行するには、他のすべてのスレッドでロックを解除する必要があります。シグナルを受信するスレッドが継続するまでブロックする pthread_cond_signal() の実装がある場合、対応するミューテックスがロックされた状態でスレッドが呼び出しに入ると、デッドロックが発生します。これは、一方の環境が正常に機能し、他方の環境が正常に機能しない理由も説明できます。たとえば、デスクトップ環境には pthread_cond_signal() へのブロッキング呼び出しがなく、組み込み環境にはあります。

于 2016-12-25T23:57:53.827 に答える