16

条件変数について学習しようとしています。条件変数が使用される一般的な状況を知りたいです。

1 つの例は、2 つのスレッドがキューにアクセスするブロッキング キューです。プロデューサー スレッドはアイテムをキューにプッシュし、コンシューマー スレッドはキューからアイテムをポップします。キューが空の場合、コンシューマ スレッドはプロデューサー スレッドからシグナルが送信されるまで待機しています。

条件変数を使用する必要があるその他の設計状況はどのようなものですか?

ただし、実際のライブ アプリケーションでの例など、経験に基づいた例を希望します。

4

5 に答える 5

2

単なるメッセージ キューよりも少し複雑な条件変数の用途の 1 つは、「ロックを共有する」ことです。この場合、さまざまなスレッドが同じ基本的な性質の微妙に異なる条件を待機しています。たとえば、(非常にずさんで単純化された) Web キャッシュがあるとします。キャッシュ内の各エントリには、存在しない、IN_PROGRESS、COMPLETE の 3 つの状態があります。

getURL:
    lock the cache
    three cases for the key:
        not present:
            add it (IN_PROGRESS)
            release the lock
            fetch the URL
            take the lock
            update to COMPLETE and store the data
            broadcast the condition variable
            goto COMPLETE
        COMPLETE:
            release the lock and return the data
        IN_PROGRESS:
            while (still IN_PROGRESS):
                wait on the condition variable
            goto COMPLETE

私は実際にこのパターンを使用してpthread_once、スケジューラーの助けを借りずに POSIX 関数のバリアントを実装しました。ごとにセマフォまたはロックを使用できずonce_control、ロックの下で初期化を行うことができなかった理由は、関数が失敗することを許可されておらず、once_control単純な初期化しかなかったためです。さらに言えば、pthread_onceそれ自体にはエラーコードが定義されていないため、失敗する可能性があるように実装しても、呼び出し元に適切なオプションが残されません...

もちろん、このパターンではスケーリングに注意する必要があります。初期化が完了するたびに、待機中のすべてのスレッドが起動してロックを取得します。そのため、システムを設計するときは、シャーディングについて非常に慎重に検討し、パフォーマンス上の問題が証明されるまで、実際にシャーディングを実装するために何もする必要はないと判断します。

于 2010-03-19T11:32:15.970 に答える
1

例として、すでに述べた消費者/生産者モデルに加えて、バリア同期での使用があります。スレッドがバリアに入るとき、バリアに入る必要のある他のスレッドがまだある場合、それらは条件変数で待機します。バリアに入る最後のスレッドは、状態を通知します。

于 2010-03-19T10:28:09.383 に答える
0

同期オブジェクトが追加された同期メッセージを送信するために使用しました。
同期オブジェクトは、「準備完了」ブール値を持つ条件変数で構成されていました。
syncMsg::send() 関数には sync->wait() があり、syncMsg::handle() 関数には sync->go() がありました。

デッドロックが発生する可能性があるため、慎重に使用する必要があります。

于 2010-03-19T12:03:07.010 に答える
0

エラーが発生しやすい Win32 Event オブジェクトの代わりに、条件変数を使用します。condvars を使用すると、偽のシグナル伝達についてそれほど心配する必要はありません。複数のイベントが発生するのを待つのも簡単です。

コンドバーはより汎用的なため、セマフォを置き換えることもできます。

于 2010-03-19T12:54:56.917 に答える
0

これがあまり役に立たないことはわかっていますが、スレッドに何かが起こるのを待つか、何かが起こるまで待つだけにしたいときはいつでも条件変数を使用します。

私が条件変数を使用する場所の非常に一般的なパターンは、バックグラウンド スレッドが数分ごとにウェイクアップして何らかの処理を行ってからスリープ状態に戻ることです。シャットダウン時に、メインスレッドはバックグラウンドスレッドに終了するように通知し、終了するように参加します。バックグラウンド スレッドは、タイムアウトを使用して状態を待機し、スリープを実行します。

バックグラウンド スレッドは、この基本的なロジックに従います

void threadFunction() {
    initialisation();

    while(! shutdown()) {
        backgroundTask();

        shutdown_condition_wait(timeout_value);
    }

    cleanup();
}

これにより、バックグラウンド スレッドが迅速かつ正常にシャットダウンされます。

そのようなスレッドが多数ある場合、メイン関数はそれぞれにシャットダウンするように通知し、次から次へと参加します。これにより、各スレッド コンポーネントが並行してシャットダウンできるようになります。

于 2010-03-19T16:10:08.183 に答える