Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Class template mpsc_weak_queue
PrevUpHomeNext

Class template mpsc_weak_queue

boost::lockfree::mpsc_weak_queue

Synopsis

// In header: <boost/lockfree/mpsc_weak_queue.hpp>

template<typename T, typename... Options> 
class mpsc_weak_queue {
public:
  // types
  typedef T                                 value_type;
  typedef implementation_defined::allocator allocator; 
  typedef implementation_defined::size_type size_type; 

  // public member functions
  bool is_lock_free() const;
  mpsc_weak_queue();
  template<typename U, 
           typename Enabler = std::enable_if< has_capacity || !use_freelist > > 
    explicit mpsc_weak_queue(typename boost::allocator_rebind< node_allocator, U >::type const &);
  template<typename Enabler = std::enable_if< has_capacity || !use_freelist > > 
    explicit mpsc_weak_queue(allocator const &);
  template<typename Enabler = std::enable_if< !has_capacity && use_freelist > > 
    explicit mpsc_weak_queue(size_type);
  template<typename Enabler = std::enable_if< !has_capacity && use_freelist > > 
    mpsc_weak_queue(size_type, allocator const &);
  mpsc_weak_queue(const mpsc_weak_queue &) = delete;
  mpsc_weak_queue & operator=(const mpsc_weak_queue &) = delete;
  mpsc_weak_queue(mpsc_weak_queue &&) = delete;
  mpsc_weak_queue & operator=(mpsc_weak_queue &&) = delete;
  template<typename Enabler = std::enable_if< can_reserve > > 
    void reserve(size_type);
  template<typename Enabler = std::enable_if< can_reserve > > 
    void reserve_unsafe(size_type);
  ~mpsc_weak_queue();
  bool empty() const;
  bool push(const T &);
  bool push(T &&);
  template<typename Enabler = std::enable_if< use_freelist > > 
    bool bounded_push(const T &);
  template<typename Enabler = std::enable_if< use_freelist > > 
    bool bounded_push(T &&);
  bool unsynchronized_push(const T &);
  bool unsynchronized_push(T &&);
  bool pop(T &);
  template<typename U, 
           typename Enabler = std::enable_if_t< std::is_constructible< U, T&& >::value > > 
    bool pop(U &);
  std::optional< T > pop(uses_optional_t);
  template<typename U> std::optional< U > pop(uses_optional_t);
  bool unsynchronized_pop(T &);
  template<typename U, 
           typename Enabler = std::enable_if_t< std::is_constructible< U, T&& >::value > > 
    bool unsynchronized_pop(U &);
  template<typename Functor> bool consume_one(Functor &&);
  template<typename Functor> bool unsynchronized_consume_one(Functor &&);
  template<typename Functor> size_t consume_all(Functor &&);
};

Description

Multi-producer/single-consumer queue based on Dmitry Vyukov's MPSC algorithm.

The push and pop methods execute in a bounded number of instructions (wait-free execution), but the queue as a whole is not lock-free in the strict sense (see Limitations).

By default, a freelist manages node memory. Freed nodes are recycled internally rather than returned to the OS until the queue is destroyed.

Limitations. A good writeup of the limitations of this algorithm is available at Ode to a Vyukov Queue.

  • Push atomicity: push exchanges the tail then links the previous node. If a producer thread terminates or stalls between these steps, the queue becomes inconsistent. The consumer will see a broken link and stop delivering elements until the producer completes the link. If the producer permanently terminates, the queue is permanently broken.

  • Non-linearizable: per-producer FIFO is preserved, but no global ordering across concurrent producers exists. pop may return false even if the queue is non-empty when a concurrent push is in progress.

Policies. 

  • boost::lockfree::freelist (default true):
    When enabled, freed nodes enter an internal freelist for reuse, avoiding repeated allocation. When disabled, the allocator handles every allocation and deallocation. Allocator operations may not be lock-free.

  • boost::lockfree::fixed_sized (default false):
    When enabled, push never performs dynamic allocation, guaranteeing lock-free behavior. Nodes reside in a fixed array addressed by index. Capacity is limited to the index type's range (typically 2^16-2). This is required for lock-free operation on platforms lacking double-width CAS.

  • boost::lockfree::capacity (optional):
    Sets queue size at compile time. Implies fixed_sized<true>.

  • boost::lockfree::allocator (default std::allocator<void>).

Requirements. 

  • T must be move-constructible.

  • T must be move-assignable.

[Note] Note

Only one consumer thread is supported. Multiple producer threads are supported.

mpsc_weak_queue public member functions

  1. bool is_lock_free() const;

    [Warning] Warning

    Only checks whether the head, tail, and freelist can be modified in a lock-free manner. On most platforms the entire implementation is lock-free when this returns true.

    Returns:

    true if the implementation is lock-free.

  2. mpsc_weak_queue();

    Construct a queue.

    Requires a capacity<> argument when freelist is enabled.

  3. template<typename U, 
             typename Enabler = std::enable_if< has_capacity || !use_freelist > > 
      explicit mpsc_weak_queue(typename boost::allocator_rebind< node_allocator, U >::type const & alloc);

    Construct a fixed-sized queue with a custom allocator.

    Requires a capacity<> argument when freelist is enabled.

  4. template<typename Enabler = std::enable_if< has_capacity || !use_freelist > > 
      explicit mpsc_weak_queue(allocator const & alloc);

    Construct a fixed-sized queue with a custom allocator.

    Requires a capacity<> argument when freelist is enabled.

  5. template<typename Enabler = std::enable_if< !has_capacity && use_freelist > > 
      explicit mpsc_weak_queue(size_type n);

    Construct a variable-sized queue.

    Allocates n nodes initially for the freelist.

    Requires that no capacity<> argument is specified and that freelist is enabled.

  6. template<typename Enabler = std::enable_if< !has_capacity && use_freelist > > 
      mpsc_weak_queue(size_type n, allocator const & alloc);

    Construct a variable-sized queue with a custom allocator.

    Allocates n nodes initially for the freelist.

    Requires that no capacity<> argument is specified and that freelist is enabled.

  7. mpsc_weak_queue(const mpsc_weak_queue &) = delete;
  8. mpsc_weak_queue & operator=(const mpsc_weak_queue &) = delete;
  9. mpsc_weak_queue(mpsc_weak_queue &&) = delete;
  10. mpsc_weak_queue & operator=(mpsc_weak_queue &&) = delete;
  11. template<typename Enabler = std::enable_if< can_reserve > > 
      void reserve(size_type n);

    Allocate n nodes for freelist

    [Note] Note

    thread-safe, may block if memory allocator blocks

    Requires:

    only valid if no capacity<> argument given

  12. template<typename Enabler = std::enable_if< can_reserve > > 
      void reserve_unsafe(size_type n);

    Allocate n nodes for freelist

    [Note] Note

    not thread-safe, may block if memory allocator blocks

    Requires:

    only valid if no capacity<> argument given

  13. ~mpsc_weak_queue();

    Destroys the queue and frees all nodes from the freelist.

  14. bool empty() const;

    Check whether the queue is empty.

    [Note] Note

    The result is only accurate when no other thread modifies the queue concurrently.

    Returns:

    true if the queue is empty, false otherwise.

  15. bool push(const T & t);

    Pushes a value to the queue.

    [Note] Note

    Thread-safe. Multiple producers may call push concurrently. When the memory pool is exhausted and the pool is not fixed-sized, a new node is allocated via the allocator, which may not be lock-free.

    Returns:

    true if the value was pushed, false if node allocation failed.

  16. bool push(T && t);

    Pushes a value to the queue.

    [Note] Note

    Thread-safe. Multiple producers may call push concurrently. When the memory pool is exhausted and the pool is not fixed-sized, a new node is allocated via the allocator, which may not be lock-free.

    Returns:

    true if the value was pushed, false if node allocation failed.

  17. template<typename Enabler = std::enable_if< use_freelist > > 
      bool bounded_push(const T & t);

    Pushes a value to the queue without allocating.

    [Note] Note

    Thread-safe. Multiple producers may call bounded_push concurrently. Unlike push, bounded_push never allocates memory; it fails when the freelist is exhausted.

    Returns:

    true if the value was pushed, false if the freelist is empty.

    Throws:

    std::bad_alloc if the allocator throws during node construction.
  18. template<typename Enabler = std::enable_if< use_freelist > > 
      bool bounded_push(T && t);

    Pushes a value to the queue without allocating.

    [Note] Note

    Thread-safe. Multiple producers may call bounded_push concurrently. Unlike push, bounded_push never allocates memory; it fails when the freelist is exhausted.

    Returns:

    true if the value was pushed, false if the freelist is empty.

    Throws:

    std::bad_alloc if the allocator throws during node construction.
  19. bool unsynchronized_push(const T & t);

    Pushes a value to the queue without synchronization.

    [Note] Note

    Not thread-safe. Only one producer thread should call unsynchronized_push. When the memory pool is exhausted and the pool is not fixed-sized, a new node is allocated via the allocator, which may not be lock-free.

    Returns:

    true if the value was pushed, false if node allocation failed.

    Throws:

    std::bad_alloc if the allocator throws during node construction.
  20. bool unsynchronized_push(T && t);

    Pushes a value to the queue without synchronization.

    [Note] Note

    Not thread-safe. Only one producer thread should call unsynchronized_push. When the memory pool is exhausted and the pool is not fixed-sized, a new node is allocated via the allocator, which may not be lock-free.

    Returns:

    true if the value was pushed, false if node allocation failed.

    Throws:

    std::bad_alloc if the allocator throws during node construction.
  21. bool pop(T & ret);

    Pops an element from the queue.

    [Note] Note

    Thread-safe and wait-free. Only one consumer thread should call pop. The output argument may be modified even when the operation fails. pop may return false even if the queue is non-empty when a concurrent push is in progress (see Limitations).

    Returns:

    true if an element was popped, false if the queue was empty.

  22. template<typename U, 
             typename Enabler = std::enable_if_t< std::is_constructible< U, T&& >::value > > 
      bool pop(U & ret);

    Pops an element from the queue.

    [Note] Note

    Thread-safe and wait-free. Only one consumer thread should call pop. The output argument may be modified even when the operation fails. pop may return false even if the queue is non-empty when a concurrent push is in progress (see Limitations).

    Template Parameters:

    U

    type to receive the popped value; U must be constructible from T (explicit or implicit).

    Returns:

    true if an element was popped, false if the queue was empty.

  23. std::optional< T > pop(uses_optional_t);

    Pops an element, returning a std::optional<T>.

    [Note] Note

    Thread-safe and wait-free. Only one consumer thread should call this overload.

    Returns:

    std::optional containing the value on success, std::nullopt if the queue is empty.

  24. template<typename U> std::optional< U > pop(uses_optional_t);

    Pops an element, returning a std::optional.

    [Note] Note

    Thread-safe and wait-free. Only one consumer thread should call this overload.

    Template Parameters:

    U

    type to receive the popped value; T must be convertible to U.

    Returns:

    std::optional<U> containing the value on success, std::nullopt if the queue is empty.

  25. bool unsynchronized_pop(T & ret);

    Pops an element without synchronization.

    [Note] Note

    Not thread-safe but wait-free. Only one consumer thread should call unsynchronized_pop. The output argument may be modified even when the operation fails.

    Returns:

    true if an element was popped, false if the queue was empty.

  26. template<typename U, 
             typename Enabler = std::enable_if_t< std::is_constructible< U, T&& >::value > > 
      bool unsynchronized_pop(U & ret);

    Pops an element without synchronization.

    [Note] Note

    Not thread-safe but wait-free. Only one consumer thread should call unsynchronized_pop.

    Template Parameters:

    U

    type to receive the popped value; U must be constructible from T (explicit or implicit).

    Returns:

    true if an element was popped, false if the queue was empty.

  27. template<typename Functor> bool consume_one(Functor && f);

    Consumes one element via a functor.

    Pops one element and applies the functor to it.

    [Note] Note

    Thread-safe and wait-free when the functor is thread-safe and non-blocking. Only one consumer thread should call this.

    Returns:

    true if an element was consumed.

  28. template<typename Functor> bool unsynchronized_consume_one(Functor && f);

    Consumes one element via a functor without synchronization.

    Pops one element and applies the functor to it.

    [Note] Note

    Not thread-safe but wait-free. Only one consumer thread should call this.

    Returns:

    true if an element was consumed.

  29. template<typename Functor> size_t consume_all(Functor && f);

    Consumes all elements via a functor.

    Sequentially pops all elements and applies the functor to each.

    [Note] Note

    Thread-safe and wait-free when the functor is thread-safe and non-blocking. Only one consumer thread should call this.

    Returns:

    the number of elements consumed.


PrevUpHomeNext