1

以下のコードは、バックグラウンド ワーカー スレッドを使用して、作業項目を 1 つずつ処理します。ワーカー スレッドは、作業項目がなくなるたびに ManualResetEvent の待機を開始します。メイン スレッドは定期的に新しい作業項目を追加し、ワーカー スレッドを起動します。

ウェイク メカニズムには競合状態があります。ワーカー スレッドが * で示される場所にあるときに、メイン スレッドによって新しい項目が追加された場合、ワーカー スレッドは起床しません。

この問題のないワーカー スレッドをウェイクアップする簡単で正しい方法はありますか?

    ManualResetEvent m_waitEvent;

    // Worker thread processes work items one by one
    void WorkerThread()
    {
        while (true)
        {
            m_waitEvent.WaitOne();
            bool noMoreItems = ProcessOneWorkItem();
            if (noMoreItems)
            {
                // *
                m_waitEvent.Reset();    // No more items, wait for more
            }
        }
    }

    // Main thread code that adds a new work item
    AddWorkItem();  
    m_waitEvent.Set();  // Wake worker thread
4

2 に答える 2

3

間違った同期メカニズムを使用しています。MRE ではなく、セマフォを使用します。セマフォは、まだ処理されていないアイテムの数を表します。1つ追加するように設定するか、1つ減らすのを待つことができます。はありませifん。常にすべてのセマフォ アクションを実行するため、競合状態は発生しません。

つまり、問題を完全に回避できます。同期プリミティブを自分で管理するのではなく、BlockingCollection. プロデューサーにアイテムを追加させ、コンシューマーにそれらを消費させます。同期はすべてそのクラスによって処理され、おそらく実装よりも効率的です。

于 2013-09-23T13:58:40.867 に答える
0

私は現在の作業項目カウンターを使用し、そのカウンターを増減する傾向があります。プロセッサ スレッドを、一度実行して完了するのではなく、そのカウンターを見てからスリープ状態にするループに変えることができます。そうすれば、アイテムが追加されたときにどこにいても、アイテムが処理されてから 1 睡眠サイクルになります。

于 2013-09-23T13:47:32.360 に答える