Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlcc_singleconsumerqueue
[Package bdlcc]

Provide a thread-aware single consumer queue of values. More...

Namespaces

namespace  bdlcc

Detailed Description

Outline
Purpose:
Provide a thread-aware single consumer queue of values.
Classes:
bdlcc::SingleConsumerQueue thread-aware single consumer queue of TYPE
Description:
This component defines a type, bdlcc::SingleConsumerQueue, that provides an efficient, thread-aware queue of values assuming a single consumer (the use of popFront, tryPopFront, and removeAll is done by one thread or a group of threads using external synchronization). The behavior of the methods popFront, tryPopFront, and removeAll is undefined unless the use is by a single consumer. This class is ideal for synchronization and communication between threads in a producer-consumer model when there is only one consumer thread.
The queue provides pushBack and popFront methods for pushing data into the queue and popping data from the queue. The queue will allocate memory as necessary to accommodate pushBack invocations (pushBack will never block and is provided for consistency with other containers). When the queue is empty, the popFront methods block until data appears in the queue. Non-blocking methods tryPushBack and tryPopFront are also provided. The tryPopFront method fails immediately, returning a non-zero value, if the queue is empty.
The queue may be placed into a "enqueue disabled" state using the disablePushBack method. When disabled, pushBack and tryPushBack fail immediately and return an error code. The queue may be restored to normal operation with the enablePushBack method.
The queue may be placed into a "dequeue disabled" state using the disablePopFront method. When dequeue disabled, popFront and tryPopFront fail immediately and return an error code. Any threads blocked in popFront when the queue is dequeue disabled return from popFront immediately and return an error code.
Template Requirements:
bdlcc::SingleConsumerQueue is a template that is parameterized on the type of element contained within the queue. The supplied template argument, TYPE, must provide both a default constructor and a copy constructor, as well as an assignment operator. If the default constructor accepts a bslma::Allocator *, TYPE must declare the uses bslma::Allocator trait (see bslma_usesbslmaallocator) so that the allocator of the queue is propagated to the elements contained in the queue.
Allocator Requirements:
Access to the allocator supplied to the constructor is internally synchronized by this component. If allocations performed by this component must be synchronized with external allocations (performed outside of this component), that synchronization must be guaranteed by the user. Using a thread-safe allocator is the common way to satisfy this requirement.
Exception Safety:
A bdlcc::SingleConsumerQueue is exception neutral, and all of the methods of bdlcc::SingleConsumerQueue provide the basic exception safety guarantee (see bsldoc_glossary).
Move Semantics in C++03:
Move-only types are supported by bdlcc::SingleConsumerQueue on C++11 platforms only (where BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES is defined), and are not supported on C++03 platforms. Unfortunately, in C++03, there are user types where a bslmf::MovableRef will not safely degrade to a lvalue reference when a move constructor is not available (types providing a constructor template taking any type), so bslmf::MovableRefUtil::move cannot be used directly on a user supplied template type. See internal bug report 99039150 for more information.
Usage:
This section illustrates intended use of this component.
Example 1: A Simple Thread Pool:
In the following example a bdlcc::SingleConsumerQueue is used to communicate between multiple "producer" threads and a single "consumer" thread. The "producers" will push work requests onto the queue, and the "consumer" will iteratively take a work request from the queue and service the request.
First, we define a utility classes that handles a simple "work item":
  struct my_WorkData {
      // Work data...
  };
Next, we provide a simple function to service an individual work item. The details are unimportant for this example:
  void myDoWork(const my_WorkData& data)
  {
      // do some stuff...
      (void)data;
  }
Then, we define a myProducer function that will push elements onto the queue until the queue is disabled. Note that the call to queue->pushFront(&item) will never block:
  void myProducer(bdlcc::SingleConsumerQueue<my_WorkData> *queue)
  {
      while (1) {
          my_WorkData item;
          if (queue->pushBack(item)) {
              return;                                               // RETURN
          }
      }
  }
Finally, we define a myConsumer function that serves multiple roles: it creates the bdlcc::SingleConsumerQueue, starts the producer threads, and then dequeues and processes work items. After completing an amount of work items, the queue is disabled for enqueueing, the producer threads are joined and the consumer uses tryPopFront until the queue is empty.
  void myConsumer(int numThreads)
  {
      enum {
          k_NUM_WORK_ITEMS = 1000
      };

      bdlcc::SingleConsumerQueue<my_WorkData> queue;

      bslmt::ThreadGroup producerThreads;
      producerThreads.addThreads(bdlf::BindUtil::bind(&myProducer, &queue),
                                 numThreads);

      my_WorkData item;

      for (int i = 0; i < k_NUM_WORK_ITEMS; ++i) {
          queue.popFront(&item);
          myDoWork(item);
      }

      queue.disablePushBack();

      producerThreads.joinAll();

      while (0 == queue.tryPopFront(&item)) {
          myDoWork(item);
      }

      ASSERT(queue.isEmpty());
  }