5

私の C++ プログラムには、pthreads (Linux 上で実行) に基づくトリガーと待機メンバー関数を持つクラス CEvent があります。待機中のプロセスが 1 つある場合、実装は非常に明白です (つまり、オンラインで多くの例を参照)。ただし、複数のスレッドがイベントを待機しており、trigger() が呼び出されたときにすべて確実にウェイクアップする必要があるという要件を満たす必要があります。2 つ目の条件として、trigger() が呼び出されたときに待機していたスレッドのみが起動する必要があります。

私の現在のコード:

void CEvent::trigger() {
    pthread_mutex_lock(&mutex);
    wakeUp = true;
    pthread_cond_broadcast(&condition)
    pthread_mutex_unlock(&mutex);
    wakeUp = false;
}

void CEvent::wait() {
    pthread_mutex_lock(&mutex);
    while (!wakeUp)
        pthread_cond_wait(&condition, &mutex)

    pthread_mutex_unlock(&mutex);
}

これは、wakeUp を false に戻す前に待機中のすべてのスレッドがウェイクアップする限り、ほとんど機能しているようです。ただし、ブロードキャストと wakeUp のリセットの間に、wait() を呼び出す他の (または同じ) スレッドもすぐにウェイクアップしますが、これは受け入れられません。ミューテキストのロック解除の前に wakeUp = false を配置すると、スレッドが起動しなくなります。

私の質問: * pthread_cond_broadcast はいつ返されますか? つまり、すべてのスレッドが起動した後にのみ戻るという保証がありますか、それとも前に戻ることができますか? * この問題に対する推奨される解決策はありますか?

4

1 に答える 1

4

私の以前の偽の答えを無視してください。トリガー スレッドがミューテックスのロックを解除する (したがって、待機中のスレッドを解放する) 時間と、wakeUp 値を設定する時間との間に競合があります。これは、別の (待機していない) スレッドが入ってきてミューテックスを取得し、真の値を確認してwakeUp待機せずに終了できることを意味します。別のバグは、待機していたスレッドwakeUpがリセット後にウェイクアップし、すぐに待機を再開することです。

これを解決する 1 つの方法は、count を使用することです。待機中の各スレッドはカウントをインクリメントし、その数のスレッドが復帰するまでトリガーは待機してから再開します。次に、これが発生するまで待機していないスレッドが待機を開始できないようにする必要があります。

// wake up "waiters" count of waiting threads
void CEvent::trigger()
{
    pthread_mutex_lock(&mutex);

    // wakey wakey
    wakeUp = true;
    pthread_cond_broadcast(&condition);

    // wait for them to awake
    while (waiters>0)
      pthread_cond_wait(&condition, &mutex);

    // stop waking threads up
    wakeUp = false;

    // let any "other" threads which were ready to start waiting, do so
    pthread_cond_broadcast(&condition);
    pthread_mutex_unlock(&mutex);
}

// wait for the condition to be notified for us
void CEvent::wait()
{
    pthread_mutex_lock(&mutex);

    // wait for us to be allowed to start waiting
    // we have to wait until any currrently being woken threads have gone
    while (wakeUp)
        pthread_cond_wait(&condition, &mutex);

    // our turn to start waiting
    waiters ++;

    // waiting
    while (!wakeUp)
        pthread_cond_wait(&condition, &mutex);

    // finished waiting, we were triggered
    waiters --;

    // let the trigger thread know we're done
    pthread_cond_broadcast(&condition);
    pthread_mutex_unlock(&mutex);
}
于 2009-05-28T09:29:58.313 に答える