Quick Links:

bal | bbl | bdl | bsl

Namespaces | Functions

Component bdlma_concurrentfixedpool
[Package bdlma]

Provide thread-safe pool of limited # of blocks of uniform size. More...

Namespaces

namespace  bdlma

Functions

void * operator new (bsl::size_t size, BloombergLP::bdlma::ConcurrentFixedPool &pool)
void operator delete (void *address, BloombergLP::bdlma::ConcurrentFixedPool &pool)

Detailed Description

Outline
Purpose:
Provide thread-safe pool of limited # of blocks of uniform size.
Classes:
bdlma::ConcurrentFixedPool thread-safe pool of limited number of blocks
See also:
Component bdlma_concurrentpool
Description:
This component implements a fully thread-safe memory pool that allocates and manages a limited number (specified at construction) of memory blocks of some uniform size (also specified at construction). A bdlma::ConcurrentFixedPool constructed to manage up to N blocks also provides an association between the address of each block and an index in the range [ 0 .. N - 1 ].
Other than this mapping between block and index, and the associated limit on the maximum number of blocks that may be simultaneously allocated, this component's semantics are identical to bdlma::ConcurrentPool. In particular, this component overloads global operator new in the same manner, and the behaviors of release and reserveCapacity are equivalent to the corresponding methods in bdlma::ConcurrentPool.
Like bdlma::ConcurrentPool, this component is intended to be used to implement out-of-place container classes that hold elements of uniform size.
Usage:
bdlma::ConcurrentFixedPool is intended to implement out-of-place container classes that hold up to a fixed number of elements, all of uniform size. Suppose we wish to implement a simple thread pool. We want the equivalent of a bsl::deque<bsl::function<void(void)> >. However, to minimize the time spent performing operations on this deque - which must be carried out under a lock - we instead store just pointers in the deque, and manage memory efficiently using bdlma::ConcurrentFixedPool. bdlma::ConcurrentFixedPool is fully thread-safe and does not require any additional synchronization.
The example below is just for the container portion of our simple thread pool. The implementation of the worker thread, and the requisite synchronization, are omitted for clarity.
  class my_JobQueue {

    public:
      // PUBLIC TYPES
      typedef bsl::function<void(void)> Job;

    private:
      // DATA
      bslmt::Mutex                d_lock;
      bsl::deque<Job *>           d_queue;
      bdlma::ConcurrentFixedPool  d_pool;
      bslma::Allocator           *d_allocator_p;

      // Not implemented:
      my_JobQueue(const my_JobQueue&);

    public:
      // CREATORS
      my_JobQueue(int maxJobs, bslma::Allocator *basicAllocator = 0);
      ~my_JobQueue();

      // MANIPULATORS
      void enqueueJob(const Job& job);

      int tryExecuteJob();
  };

  my_JobQueue::my_JobQueue(int maxJobs, bslma::Allocator *basicAllocator)
  : d_queue(basicAllocator)
  , d_pool(sizeof(Job), maxJobs, basicAllocator)
  , d_allocator_p(bslma::Default::allocator(basicAllocator))
  {
  }

  my_JobQueue::~my_JobQueue()
  {
      Job *jobPtr;
      while (!d_queue.empty()) {
          jobPtr = d_queue.front();
          jobPtr->~Job();
          d_queue.pop_front();
      }
  }

  void my_JobQueue::enqueueJob(const Job& job)
  {
      Job *jobPtr = new (d_pool) Job(job, d_allocator_p);
      d_lock.lock();
      d_queue.push_back(jobPtr);
      d_lock.unlock();
  }

  int my_JobQueue::tryExecuteJob()
  {
      d_lock.lock();
      if (d_queue.empty()) {
          d_lock.unlock();
          return -1;                                                // RETURN
      }
      Job *jobPtr = d_queue.front();
      d_queue.pop_front();
      d_lock.unlock();
      (*jobPtr)();
      d_pool.deleteObject(jobPtr);
      return 0;
  }
Note that in the destructor, there is no need to deallocate the individual job objects - the destructor of bdlma::ConcurrentFixedPool will release any remaining allocated memory. However, it is necessary to invoke the destructors of all these objects, as the destructor of bdlma::ConcurrentFixedPool will not do so.

Function Documentation

void* operator new ( bsl::size_t  size,
BloombergLP::bdlma::ConcurrentFixedPool &  pool 
) [inline]

Allocate memory of the specified size bytes from the specified pool, and return the address of the allocated memory. The behavior is undefined unless size is the same as the objectSize with which pool was constructed. Note that an object may allocate additional memory internally within its constructor, requiring the allocator to be passed in as a constructor argument:

      my_Type *newMyType(bdlma::ConcurrentFixedPool  *pool,
                         bslma::Allocator *basicAllocator) {
          return new (*pool) my_Type(..., basicAllocator);
      }

Note also that the analogous version of operator delete should not be called directly. Instead, this component provides a template member function bdlma::ConcurrentFixedPool::deleteObject parameterized by TYPE that performs the equivalent of the following:

      void deleteMyType(bdlma::ConcurrentFixedPool *pool, my_Type *t) {
          t->~my_Type();
          pool->deallocate(t);
      }
void operator delete ( void *  address,
BloombergLP::bdlma::ConcurrentFixedPool &  pool 
) [inline]

Use the specified pool to deallocate the memory at the specified address. The behavior is undefined unless address was allocated using pool and has not already been deallocated. This operator is supplied solely to allow the compiler to arrange for it to be called in case of an exception. Client code should not call it; use bdlma::ConcurrentFixedPool::deleteObject() instead.