0

わかりました、2 つの追加スレッドを持つアプリケーションがあります。

スレッド 1 はオブジェクト O にアクセスし、オブジェクト O の一部である両端キューにデータを挿入し、カウンタ変数をインクリメントします。

スレッド 2 はオブジェクト O にアクセスし、deque からデータを取り出して削除し、カウンター変数をデクリメントします。

これは予期しない結果をもたらすことが判明しました。これは、1 つのスレッドが両端キュー内に x 要素があることを通知し、もう 1 つのスレッドが要素がないことを通知するためです。ある種の同期を使用する必要があると思います。セマフォを使用しようとしましたが、動作しなかったため誤解していたはずです ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms686946(v=vs.85).aspx )。

2 つのスレッドからグローバル オブジェクトにアクセスする方法を知りたいです。グローバル オブジェクト O へのアクセスは頻繁に発生することに注意してください。これは、アクセスが while ループ内にあり、結果として挿入とポーリングが繰り返されるためです。(可能な解決策は、他のスレッドがオブジェクトにアクセスするのをブロックし、それによって while ループをブロックしますか?)

これまでのところ、セマフォとミューテックスしか知りませんが、それらを使用したことはありません。親切に教えてください。

4

2 に答える 2

1

最も簡単な方法は、排他的な方法で使用したいコードの周りでEnterCriticalSection/を使用することです:LeaveCriticalSection

CRITICAL_SECTION critSect;

// Later in the code
EnterCriticalSection(&critSect);
// Do stuff with O
LeaveCriticalSection(&critSect);

もちろん、これを両方のスレッドで使用します。一度に 1 つのスレッドのみが enter/leave ゾーン内に存在できます。はEnterCriticalSection、他のスレッドが呼び出すまでブロックしますLeaveCriticalSection

于 2012-10-07T19:51:00.050 に答える
0

オブジェクトを変更する可能性のある 1 回のアクセスで複数のスレッドからオブジェクトにアクセスする場合は、いくつかの同期が必要です。説明したシナリオでは、必要なスレッド保護とシグナル伝達を行うキュー クラスが必要になる場合があります。簡単な実装を次に示します。

#include <mutex>
#include <condition_variable>
#include <deque>

template <typename T>
class queue
{
private:
    std::mutex              d_mutex;
    std::condition_variable d_condition;
    std::deque<T>           d_queue;
public:
    void push(T const& value) {
        {
            std::unique_lock<std::mutex> lock(this->d_mutex);
            d_queue.push_front(value);
        }
        this->d_condition.notify_one();
    }
    T pop() {
        std::unique_lock<std::mutex> lock(this->d_mutex);
        this->d_condition.wait(lock, [=]{ return !this->d_queue.empty(); });
        T rc(std::move(this->d_queue.back()));
        this->d_queue.pop_back();
        return rc;
    }
};

このコードは C++ 2011 の構造を使用していますが、標準化されていないことを除いて、それらの使用を避け、代わりに C++ 2003 の構造を使用するように簡単に変更できます。

重要なポイントは次のとおりです。

  1. Astd::mutexは、スレッドのみが一度にキューにアクセスすることを確認するために使用されます。
  2. 何かをキューに入れると、ミューテックスのロックが取得され、オブジェクトがキューに挿入されます。オブジェクトが挿入されると、ロックが自動的に解除され、条件変数が通知されます。
  3. キューから何かを抽出すると、ミューテックスのロックが取得され、スレッドは条件変数を使用してキューが空でなくなるのを待ちます: キューに何かが既にある場合、条件はすぐに返されますtruewait()条件が再評価される時点でシグナルを受け取るまでスリープ状態になります。条件変数への偽のウェイクアップがある可能性があるため、条件が複数回評価される場合があることに注意してください。
  4. ラムダはそのコンテキストを値でキャプチャします。実際にキャプチャするのはthis;だけです。メンバー変数はローカル コンテキストの一部ではないため、直接キャプチャすることはできません。
  5. からの結果pop()は値によって返されます。ロックが解放された瞬間にコンテナが変更される可能性があり、オブジェクトが適切な場所に配置されていたとしても、参照によってオブジェクトを返すことができなくなります。

これがおもちゃの例である主な理由は、システムをシャットダウンする適切な方法がないためです。スレッドがキューでブロックされている場合、スレッドは別のオブジェクトが存在するまで待機します。実際の実装では、シャットダウンする時間になったことを通知する何らかの方法があり、おそらく から例外がスローされpop()ます。また、オブジェクトの抽出を強制的にブロックしないキューがあると便利な場合もあります。代わりに、try_pop()ロックを取得し、キューが空でないかどうかをチェックし、結果の抽出とオブジェクトまたは信号の失敗に応じてチェックする関数があります。ただし、このような機能は簡単に実装できます。

于 2012-10-07T20:55:08.123 に答える