1

プロデューサー/コンシューマーに対して正常に動作する次の c++11 コードについての簡単な質問です。問題は、DataQueue をシャットダウンしてすべてのコンシューマーを停止することです。問題は消費者が popWait() を呼び出すだけでブロックされる可能性があるためです。この場合、コンシューマーをシャットダウンするにはどうすればよいですか? これはおそらく修正が必要な設計上の問題です。このコードは理想的にはディスラプター パターンなどを使用してキューのロックを解除する必要があるため、パフォーマンス ヒットが発生しないようにしています。とはいえ、プロデューサーがシャットダウンしたときにポップ待機関数の呼び出しを停止することを消費者に知らせる簡単な方法があるかどうか疑問に思っていました。トリッキーな部分は、キューにまだデータがある場合にシャットダウンすることです。コンシューマーがデータの取得を完了するまで待つ必要があります。私は、消費者が独自のシャットダウンを持っているがアイデアを受け入れる解決策があると信じています. 前もって感謝します。

#ifndef __DataQueue_h__
#define __DataQueue_h__

#include <mutex>
#include <queue>
#include <condition_variable>
#include <chrono>

template <typename DataT>
class DataQueue
{
  public:

  DataQueue (): _shutdown(false), _waitTime(5), _itemAvailable() {}

  void push ( const DataT& data )       
  {
    std::unique_lock<std::mutex> lock(_mutex);
    queue.push(data);
    _itemAvailable.notify_one();
  }

// worked fine until I need to shutdown services... then some were blocked
  DataT popWait()
  {
    std::unique_lock<std::mutex> lock(_mutex);

    if(queue.empty())
    {
      _itemAvailable.wait(lock);
    }

    DataT temp(queue.front());
    queue.pop();

    return temp;
  }

  inline void shutdown()
  {
    _shutdown = true;
  }

  private:
  std::queue<DataT> queue;
  bool _shutdown;
  unsigned int _waitTime;
  std::mutex _mutex;
  std::condition_variable _itemAvailable;

};

#endif
4

3 に答える 3

1

shutdown1 つのアイデアは、 1への呼び出しですべてのコンシューマをウェイクアップすることです。このpopWaitメソッドでは、から戻ったときにシャットダウン フラグが設定されているかどうかを確認できますwait

#include <atomic>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <chrono>

template <typename DataT>
class DataQueue
{
public:
    DataQueue (): _shutdown(false), _itemAvailable() {}

    void push ( const DataT& data )       
    {
        std::unique_lock<std::mutex> lock(_mutex);
        queue.push(data);
        _itemAvailable.notify_one();
    }

    Maybe<DataT> popWait()
    {
        std::unique_lock<std::mutex> lock(_mutex);

        while(queue.empty() && !_shutdown)
        {
          _itemAvailable.wait(lock);
        }

        Maybe<DataT> data;
        // leave pending data in the queue
        if (_shutdown) 
        {
            // consumers should stop polling when receiving an 'empty' value
            return data;
        }

        data.add(queue.front());
        queue.pop();   
        return data;
    }

    inline void shutdown()
    {
        _shutdown = true;
        _itemAvailable.notify_all();
    }

private:
    std::queue<DataT> queue;
    std::atomic<bool> _shutdown;
    std::mutex _mutex;
    std::condition_variable _itemAvailable;
};

popWait の戻り値

すべての同期とシグナリングとは別に、 の戻り値も再検討する必要がありますpopWait。ジェネリックshutdown()メソッドを実装する場合、つまり特別なセンチネル値をキュー自体に詰め込まずにpopWait、プロデューサーが停止したことを示す「値」を返すことができる必要があります。おそらくMaybe<DataT>2のようなテンプレートです。私は、それMaybe<DataT>が返さDataTれるか、何も返されない可能性があると考えています。その場合、消費者はポーリングを停止します。

template<typename DataT>
class Maybe 
{
   DataT _data;
   bool _empty;

pulic:
   Maybe() : _data(), _empty(true) {};

   void add(const DataT& raData)
   {
      _data=raData;
      _empty=false;
   }

   bool isEmpty() const
   {
      return _empty;
   }

   DataT get() const
   {
      return _data;
   }
}

これはかなり原始的なインターフェースです。必要に応じて延長できます。

1 ComicSansMSは、メモリの並べ替えの問題を回避するために_shutdownメンバー変数を宣言する必要があることを指摘しました。std::atmic<bool>ヘッドアップをありがとう。

2私はちょうどつまずいたstd::optional<T>(C++14 の新機能)、それは本質的に私が念頭に置いていたものです。

于 2013-07-02T07:25:51.483 に答える
0

popWaitキューが空であるか、真であるかを確認できます_shutDown。後者の場合、呼び出し元にデータを要求しないように通知します (例外をスローする (私の意見では最適ではありません)、またはメソッド シグネチャを少し再設計します)。次に、メソッドでnotifyAll()呼び出しを行うだけです。shutdown()

于 2013-07-02T06:28:49.507 に答える