web-dev-qa-db-fra.com

C++ équivalent à BlockingQueue de Java

Je suis en train de porter du code Java sur C++, et une section particulière utilise une file d'attente BlockingQueue pour transmettre les messages de nombreux producteurs à un seul consommateur.

Si vous n'êtes pas familier avec ce qu'est une Java BlockingQueue, il s'agit simplement d'une file d'attente ayant une capacité matérielle, qui expose les méthodes thread-safe à mettre () et à prendre () dans la file d'attente. put () bloque si la file est pleine, et take () bloque si la file est vide. Des versions sensibles à la temporisation de ces méthodes sont également fournies.

Les délais d'attente sont pertinents pour mon cas d'utilisation, donc une recommandation qui les fournit est idéale. Sinon, je peux en coder moi-même.

J'ai cherché sur Google et parcouru rapidement les bibliothèques Boost et je ne trouve rien de tel. Peut-être que je suis aveugle ici ... mais est-ce que quelqu'un connaît une bonne recommandation?

Merci!

23
Ben

Sa taille n'est pas fixe et ne prend pas en charge les délais, mais voici une implémentation simple d'une file d'attente que j'avais postée récemment à l'aide de constructions C++ 2011:

#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;
    }
};

Il devrait être trivial d'étendre et d'utiliser une attente chronométrée pour le popping. La principale raison pour laquelle je ne l'ai pas fait est que je ne suis pas satisfait des choix d'interface auxquels j'ai pensé jusqu'à présent.

39
Dietmar Kühl

Voici un exemple d'une file d'attente de blocage avec demande d'arrêt feature:

template <typename T> class BlockingQueue {
  std::condition_variable _cvCanPop;
  std::mutex _sync;
  std::queue<T> _qu;
  bool _bShutdown = false;

public:
  void Push(const T& item)
  {
    {
      std::unique_lock<std::mutex> lock(_sync);
      _qu.Push(item);
    }
    _cvCanPop.notify_one();
  }

  void RequestShutdown() {
    {
      std::unique_lock<std::mutex> lock(_sync);
      _bShutdown = true;
    }
    _cvCanPop.notify_all();
  }

  bool Pop(T &item) {
    std::unique_lock<std::mutex> lock(_sync);
    for (;;) {
      if (_qu.empty()) {
        if (_bShutdown) {
          return false;
        }
      }
      else {
        break;
      }
      _cvCanPop.wait(lock);
    }
    item = std::move(_qu.front());
    _qu.pop();
    return true;
  }
};
1
Serge Rogatch

BlockingCollection est une classe de collection sécurisée pour les threads C++ 11 qui est modélisée d'après la classe .NET BlockingCollection.

Il prend en charge les éléments suivants:

  • Implémentation du schéma classique producteur/consommateur (variable de condition, mutex)
  • Ajout et prise simultanés d'éléments de plusieurs threads.
  • Capacité maximale facultative.
  • Les opérations d'insertion et de suppression qui bloquent lorsque la collection est vide ou complète.
  • Insertion et suppression "essayer" des opérations qui ne bloquent pas ou qui bloquent jusqu'à une période de temps donnée de .
  • Opérations «en bloc» d'insertion et de retrait permettant d'ajouter ou de prendre plusieurs éléments à la fois.
  • FIFO, LIFO, opérations d'insertion et de suppression basées sur les priorités.
  • Réduit les conflits, les réveils et les conflits en gérant un sous-ensemble actif de threads de production et de consommation.
  • Prise en charge de la boucle basée sur la plage.
0
gm127