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:
-
- 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 {
mutable bslmt::Mutex d_mutex;
bsl::vector<TYPE> d_elements;
ThreadEnabledVector(const ThreadEnabledVector&);
ThreadEnabledVector& operator=(const ThreadEnabledVector&);
public:
ThreadEnabledVector(bslma::Allocator *basicAllocator = 0)
: d_elements(basicAllocator)
{
}
~ThreadEnabledVector() {}
int pushBack(const TYPE& value)
{
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)
{
bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
d_elements[index] = value;
}
TYPE element(int index) const
{
bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
return d_elements[index];
}
int length() const
{
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 {
private:
AddressBook_PrivateData(const AddressBook_PrivateData&);
public:
bslmt::Mutex d_mutex;
bdlma::ConcurrentAllocatorAdapter
d_allocatorAdapter;
AddressBook_PrivateData(bslma::Allocator *basicAllocator = 0)
: d_allocatorAdapter(&d_mutex, basicAllocator)
{
}
};
class AddressBook : private AddressBook_PrivateData {
ThreadEnabledVector<bsl::string> d_names;
ThreadEnabledVector<bsl::string> d_addresses;
private:
AddressBook(const AddressBook&);
public:
AddressBook(bslma::Allocator *basicAllocator = 0)
: AddressBook_PrivateData(basicAllocator)
, d_names(&d_allocatorAdapter)
, d_addresses(&d_allocatorAdapter)
{
}
~AddressBook()
{
}
int addName(const bsl::string& name)
{
return d_names.pushBack(name);
}
int addAddress(const bsl::string& address)
{
return d_addresses.pushBack(address);
}
bsl::string name(int index) const
{
return d_names.element(index);
}
bsl::string address(int index) const
{
return d_addresses.element(index);
}
int numNames() const
{
return d_names.length();
}
int numAddresses() const
{
return d_addresses.length();
}
};