// bdlma_concurrentallocatoradapter.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BDLMA_CONCURRENTALLOCATORADAPTER #define INCLUDED_BDLMA_CONCURRENTALLOCATORADAPTER #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a thread-enabled adapter for the allocator protocol. // //@CLASSES: // bdlma::ConcurrentAllocatorAdapter: thread-enabled allocator adapter // //@SEE_ALSO: bslma_allocator, 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(); // } // }; //.. #include <bdlscm_version.h> #include <bslma_allocator.h> #include <bslma_default.h> #include <bslmt_mutex.h> #include <bsls_types.h> #include <bslmt_mutex.h> namespace BloombergLP { namespace bdlma { // ================================ // class ConcurrentAllocatorAdapter // ================================ class ConcurrentAllocatorAdapter : public bslma::Allocator { // This class defines an implementation of the 'bslma::Allocator' protocol // that "decorates" (wraps) a concrete 'bslma::Allocator' to ensure // thread-safe access to the decorated allocator. // DATA bslmt::Mutex *d_mutex_p; // synchronizer for operations on the // allocator (held, not owned) bslma::Allocator *d_allocator_p; // allocator (held, not owned) // NOT IMPLEMENTED ConcurrentAllocatorAdapter(const ConcurrentAllocatorAdapter&); ConcurrentAllocatorAdapter& operator=(const ConcurrentAllocatorAdapter&); public: // CREATORS ConcurrentAllocatorAdapter(bslmt::Mutex *mutex, bslma::Allocator *basicAllocator); // Create a thread-enabled allocator adapter that uses the specified // 'mutex' to synchronize access to the specified 'basicAllocator'. If // 'basicAllocator' is 0, the currently installed default allocator is // used. virtual ~ConcurrentAllocatorAdapter(); // Destroy this thread-enabled allocator adapter. // MANIPULATORS virtual void *allocate(bsls::Types::size_type numBytes); // Return a newly-allocated block of memory of (at least) the specified // 'numBytes'. If 'numBytes' is 0, a null pointer is returned with no // other effect. If this allocator cannot return the requested number // of bytes, then it will throw a 'bsl::bad_alloc' exception in an // exception-enabled build, or else will abort the program in a // non-exception build. Note that the alignment of the address // returned conforms to the platform requirement for any object of the // 'numBytes'. virtual void deallocate(void *address); // Return the memory at the specified 'address' back to this allocator. // If 'address' is 0, this function has no effect. The behavior is // undefined unless 'address' was allocated using this allocator and // has not since been deallocated. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // -------------------------------- // class ConcurrentAllocatorAdapter // -------------------------------- // CREATORS inline ConcurrentAllocatorAdapter::ConcurrentAllocatorAdapter( bslmt::Mutex *mutex, bslma::Allocator *basicAllocator) : d_mutex_p(mutex) , d_allocator_p(bslma::Default::allocator(basicAllocator)) { } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2016 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------