Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlma_concurrentallocatoradapter
[Package bdlma]

Provide a thread-enabled adapter for the allocator protocol. More...

Namespaces

namespace  bdlma

Detailed Description

Outline
Purpose:
Provide a thread-enabled adapter for the allocator protocol.
Classes:
bdlma::ConcurrentAllocatorAdapter thread-enabled allocator adapter
See also:
Component bslma_allocator, Component bdlma_concurrentmultipool
Description:
This component provides an adapter, bdlma::ConcurrentAllocatorAdapter, that implements the bslma::Allocator protocol and provides synchronization for operations on an allocator supplied at construction using a mutex also supplied at construction.
   ,-----------------------------------.
  (  bdlma::ConcurrentAllocatorAdapter  )
   `-----------------------------------'
                     |                ctor/dtor
                     V
             ,-----------------.
            ( bslma::Allocator  )
             `-----------------'
                            allocate
                            deallocate
Thread Safety:
bdlma::ConcurrentAllocatorAdapter is thread-enabled, meaning any operation on the same instance can be safely invoked from any thread.
Usage:
In the following usage example, we develop a simple AddressBook class containing two thread-enabled vectors of strings: one for names, the other for addresses. We use a bdlma::ConcurrentAllocatorAdapter to synchronize memory allocations across our two thread-enabled vectors. For the purpose of this discussion, we first define a simple thread-enabled vector:
  template <class TYPE>
  class ThreadEnabledVector {
      // This class defines a trivial thread-enabled vector.

      // DATA
      mutable bslmt::Mutex d_mutex;     // synchronize access
      bsl::vector<TYPE>    d_elements;  // underlying list of strings

      // NOT IMPLEMENTED
      ThreadEnabledVector(const ThreadEnabledVector&);
      ThreadEnabledVector& operator=(const ThreadEnabledVector&);

    public:
      // CREATORS
      ThreadEnabledVector(bslma::Allocator *basicAllocator = 0)
          // Create a thread-enabled vector.  Optionally specify a
          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
          // 0, the currently installed default allocator is used.
      : d_elements(basicAllocator)
      {
      }

      ~ThreadEnabledVector() {}
          // Destroy this thread-enabled vector object.

      // MANIPULATORS
      int pushBack(const TYPE& value)
          // Append the specified 'value' to this thread-enabled vector and
          // return the index of the new element.
      {
          bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
          d_elements.push_back(value);
          return static_cast<int>(d_elements.size()) - 1;
      }

      void set(int index, const TYPE& value)
          // Set the element at the specified 'index' in this thread-enabled
          // vector to the specified 'value'.  The behavior is undefined
          // unless '0 <= index < length()'.
      {
          bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
          d_elements[index] = value;
      }

      // ACCESSORS
      TYPE element(int index) const
          // Return the value of the element at the specified 'index' in this
          // thread-enabled vector.  Note that elements are returned *by*
          // *value* because references to elements managed by this container
          // may be invalidated by another thread.
      {
          bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
          return d_elements[index];
      }

      int length() const
          // Return the number of elements in this thread-enabled vector.
      {
          bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
          return static_cast<int>(d_elements.size());
      }
  };
We use this thread-enabled vector to create a AddressBook class. However, we use the bdlma::ConcurrentAllocatorAdapter to prevent our two (thread-enabled) vectors from attempting synchronous memory allocations from our (potentially) non-thread safe bslma::Allocator. Note that we define a local class, AddressBook_PrivateData, in order to guarantee that d_allocatorAdapter and d_mutex are initialized before the thread-enabled vectors that depend on them:
  struct AddressBook_PrivateData {
      // This 'struct' contains a mutex and an allocator adapter.  The
      // 'AddressBook' class will inherit from this structure, ensuring that
      // the mutex and adapter are initialized before other member variables
      // that depend on them.

    private:
      // Not implemented:
      AddressBook_PrivateData(const AddressBook_PrivateData&);

    public:
      bslmt::Mutex           d_mutex;             // synchronize allocator

      bdlma::ConcurrentAllocatorAdapter
                            d_allocatorAdapter;  // adapter for allocator

      AddressBook_PrivateData(bslma::Allocator *basicAllocator = 0)
          // Create a empty AddressBook private data object.  Optionally
          // specify a 'basicAllocator' used to supply memory.  If
          // 'basicAllocator' is 0, the currently installed default allocator
          // is used.
      : d_allocatorAdapter(&d_mutex, basicAllocator)
      {
      }
  };

  class AddressBook : private AddressBook_PrivateData {
      // This 'class' defines a thread-enabled AddressBook containing vectors
      // of names and addresses.  Note that this class uses private
      // inheritance to ensure that the allocator adapter and mutex are
      // initialized before the vectors of names and addresses.

      // DATA
      ThreadEnabledVector<bsl::string> d_names;      // list of names
      ThreadEnabledVector<bsl::string> d_addresses;  // list of addresses

    private:
      // Not implemented:
      AddressBook(const AddressBook&);

    public:
      // CREATORS
      AddressBook(bslma::Allocator *basicAllocator = 0)
          // Create an empty AddressBook for storing names and addresses.
          // Optionally specify a 'basicAllocator' used to supply memory.  If
          // 'basicAllocator' is 0, the currently installed default allocator
          // is used.
      : AddressBook_PrivateData(basicAllocator)
      , d_names(&d_allocatorAdapter)
      , d_addresses(&d_allocatorAdapter)
      {
      }

      ~AddressBook()
          // Destroy this AddressBook.
      {
      }

      // MANIPULATORS
      int addName(const bsl::string& name)
          // Add the specified 'name' to this AddressBook and return the
          // index of the newly-added name.
      {
          return d_names.pushBack(name);
      }

      int addAddress(const bsl::string& address)
          // Add the specified 'address' to this AddressBook and return the
          // index of the newly-added address.
      {
          return d_addresses.pushBack(address);
      }

      // ACCESSORS
      bsl::string name(int index) const
          // Return the value of the name at the specified 'index' in this
          // AddressBook.
      {
          return d_names.element(index);
      }

      bsl::string address(int index) const
          // Return the value of the address at the specified 'index' in this
          // AddressBook.
      {
          return d_addresses.element(index);
      }

      int numNames() const
          // Return the number of names in this AddressBook.
      {
          return d_names.length();
      }

      int numAddresses() const
          // Return the number of addresses in this AddressBook.
      {
          return d_addresses.length();
      }
  };