BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_concurrentmultipool.h
Go to the documentation of this file.
1/// @file bdlma_concurrentmultipool.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_concurrentmultipool.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_CONCURRENTMULTIPOOL
9#define INCLUDED_BDLMA_CONCURRENTMULTIPOOL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlma_concurrentmultipool bdlma_concurrentmultipool
15/// @brief Provide a memory manager to manage pools of varying block sizes.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlma
19/// @{
20/// @addtogroup bdlma_concurrentmultipool
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlma_concurrentmultipool-purpose"> Purpose</a>
25/// * <a href="#bdlma_concurrentmultipool-classes"> Classes </a>
26/// * <a href="#bdlma_concurrentmultipool-description"> Description </a>
27/// * <a href="#bdlma_concurrentmultipool-thread-safety"> Thread Safety </a>
28/// * <a href="#bdlma_concurrentmultipool-configuration-at-construction"> Configuration at Construction </a>
29/// * <a href="#bdlma_concurrentmultipool-usage"> Usage </a>
30/// * <a href="#bdlma_concurrentmultipool-example-1-using-a-bdlma-concurrentmultipool-directly"> Example 1: Using a bdlma::ConcurrentMultipool Directly </a>
31/// * <a href="#bdlma_concurrentmultipool-example-2-implementing-an-allocator-using-bdlma-concurrentmultipool"> Example 2: Implementing an Allocator Using bdlma::ConcurrentMultipool </a>
32///
33/// # Purpose {#bdlma_concurrentmultipool-purpose}
34/// Provide a memory manager to manage pools of varying block sizes.
35///
36/// # Classes {#bdlma_concurrentmultipool-classes}
37///
38/// - bdlma::ConcurrentMultipool: memory manager that manages pools of blocks
39///
40/// @see bdlma_concurrentpool, bdlmca_multipoolallocator
41///
42/// # Description {#bdlma_concurrentmultipool-description}
43/// This component implements a memory manager,
44/// `bdlma::ConcurrentMultipool`, that maintains a configurable number of
45/// `bdlma::ConcurrentPool` objects, each dispensing memory blocks of a unique
46/// size. The `bdlma::ConcurrentPool` objects are placed in an array, starting
47/// at index 0, with each successive pool managing memory blocks of a size twice
48/// that of the previous pool. Each multipool allocation (deallocation) request
49/// allocates memory from (returns memory to) the internal pool managing memory
50/// blocks of the smallest size not less than the requested size, or else from a
51/// separately managed list of memory blocks, if no internal pool managing
52/// memory block of sufficient size exists. Both the `release` method and the
53/// destructor of a `bdlma::ConcurrentMultipool` release all memory currently
54/// allocated via the object.
55///
56/// A `bdlma::ConcurrentMultipool` can be depicted visually:
57/// @code
58/// +-----+--- memory blocks of 8 bytes
59/// | |
60/// ======== ----- ----- ------------
61/// |8 bytes |---->| | | ... |
62/// >========< =====^=====^============
63/// |16 bytes|
64/// >========< \___________ __________/
65/// |32 bytes| V
66/// >========< a "chunk"
67/// | |
68/// | ... |
69/// | |
70/// ========
71/// |
72/// +------- array of 'bdlma::ConcurrentPool'
73/// @endcode
74/// Note that a "chunk" is a large, contiguous block of memory, internal to a
75/// `bdlma::ConcurrentPool` maintained by the multipool, from which memory
76/// blocks of uniform size are dispensed to users.
77///
78/// ## Thread Safety {#bdlma_concurrentmultipool-thread-safety}
79///
80///
81/// `bdlma::ConcurrentMultipool` is *fully thread-safe*, meaning any operation
82/// on the same object can be safely invoked from any thread.
83///
84/// ## Configuration at Construction {#bdlma_concurrentmultipool-configuration-at-construction}
85///
86///
87/// When creating a `bdlma::ConcurrentMultipool`, clients can optionally
88/// configure:
89///
90/// 1. NUMBER OF POOLS -- the number of internal pools (the block size managed
91/// by the first pool is eight bytes, with each successive pool managing
92/// block of a size twice that of the previous pool).
93/// 2. GROWTH STRATEGY -- geometrically growing chunk size starting from 1 (in
94/// terms of the number of memory blocks per chunk), or fixed chunk size,
95/// specified as either:
96/// - the unique growth strategy for all pools, or
97/// - (if the number of pools is specified) an array of growth strategies
98/// corresponding to each individual pool
99/// If the growth strategy is not specified, geometric growth is used for all
100/// pools.
101/// 3. MAX BLOCKS PER CHUNK -- the maximum number of memory blocks within a
102/// chunk, specified as either:
103/// - the unique maximum-blocks-per-chunk value for all of the pools, or
104/// - an array of maximum-blocks-per-chunk values corresponding to each
105/// individual pool.
106/// If the maximum blocks per chunk is not specified, an
107/// implementation-defined default value is used. Note that the maximum
108/// blocks per chunk can be configured only if the number of pools is also
109/// configured.
110/// 4. BASIC ALLOCATOR -- the allocator used to supply memory (to replenish an
111/// internal pool, or directly if the maximum block size is exceeded). If
112/// not specified, the currently installed default allocator (see
113/// @ref bslma_default ) is used.
114///
115/// A default-constructed multipool has a relatively small,
116/// implementation-defined number of pools `N` with respective block sizes
117/// ranging from `2^3 = 8` to `2^(N+2)`. By default, the initial chunk size,
118/// (i.e., the number of blocks of a given size allocated at once to replenish a
119/// pool's memory) is 1, and each pool's chunk size grows geometrically until it
120/// reaches an implementation-defined maximum, at which it is capped. Finally,
121/// unless otherwise specified, all memory comes from the allocator that was the
122/// currently installed default allocator at the time the
123/// `bdlma::ConcurrentMultipool` was created.
124///
125/// Using the various pooling options described above, we can configure the
126/// number of pools maintained, whether replenishment should be adaptive (i.e.,
127/// geometric starting with 1) or fixed at a maximum chunk size, what that
128/// maximum chunk size should be (which need not be an integral power of 2), and
129/// the underlying allocator used to supply memory. Note that both GROWTH
130/// STRATEGY and MAX BLOCKS PER CHUNK can be specified separately either as a
131/// single value applying to all of the maintained pools, or as an array of
132/// values, with the elements applying to each individually maintained pool.
133///
134///
135/// ## Usage {#bdlma_concurrentmultipool-usage}
136///
137///
138/// This section illustrates intended use of this component.
139///
140/// ### Example 1: Using a bdlma::ConcurrentMultipool Directly {#bdlma_concurrentmultipool-example-1-using-a-bdlma-concurrentmultipool-directly}
141///
142///
143/// A `bdlma::ConcurrentMultipool` can be used by containers that hold different
144/// types of elements, each of uniform size, for efficient memory allocation of
145/// new elements. Suppose we have a factory class, `my_MessageFactory`, that
146/// creates messages based on user requests. Each message is created with the
147/// most efficient memory storage possible - using predefined 8-byte, 16-byte
148/// and 32-byte buffers. If the message size exceeds the three predefined
149/// values, a generic message is used. For efficient memory allocation of
150/// messages, we use a `bdlma::ConcurrentMultipool`.
151///
152/// First, we define our message types as follows:
153/// @code
154/// class my_MessageFactory;
155///
156/// class my_Message {
157/// // This class represents a general message interface that provides a
158/// // 'getMessage' method for clients to retrieve the underlying message.
159///
160/// public:
161/// // CREATORS
162/// virtual ~my_Message() {}
163/// // Destroy this object.
164///
165/// // ACCESSORS
166/// virtual const char *getMessage() = 0;
167/// // Return the null-terminated message string.
168/// };
169///
170/// class my_SmallMessage : public my_Message {
171/// // This class represents an 8-byte message (including null terminator).
172///
173/// // DATA
174/// char d_buffer[8];
175///
176/// // FRIEND
177/// friend class my_MessageFactory;
178///
179/// // NOT IMPLEMENTED
180/// my_SmallMessage(const my_SmallMessage&);
181/// my_SmallMessage& operator=(const my_SmallMessage&);
182///
183/// // PRIVATE CREATORS
184/// my_SmallMessage(const char *msg, int length)
185/// {
186/// assert(length <= 7);
187///
188/// bsl::memcpy(d_buffer, msg, length);
189/// d_buffer[length] = '\0';
190/// }
191///
192/// virtual ~my_SmallMessage() {}
193/// // Destroy this object.
194///
195/// // PRIVATE ACCESSORS
196/// virtual const char *getMessage()
197/// {
198/// return d_buffer;
199/// }
200/// };
201///
202/// class my_MediumMessage : public my_Message {
203/// // This class represents a 16-byte message (including null
204/// // terminator).
205///
206/// // DATA
207/// char d_buffer[16];
208///
209/// // FRIEND
210/// friend class my_MessageFactory;
211///
212/// // NOT IMPLEMENTED
213/// my_MediumMessage(const my_MediumMessage&);
214/// my_MediumMessage& operator=(const my_MediumMessage&);
215///
216/// // PRIVATE CREATORS
217/// my_MediumMessage(const char *msg, int length)
218/// {
219/// assert(length <= 15);
220///
221/// bsl::memcpy(d_buffer, msg, length);
222/// d_buffer[length] = '\0';
223/// }
224///
225/// virtual ~my_MediumMessage() {}
226/// // Destroy this object.
227///
228/// // PRIVATE ACCESSORS
229/// virtual const char *getMessage()
230/// {
231/// return d_buffer;
232/// }
233/// };
234///
235/// class my_LargeMessage : public my_Message {
236/// // This class represents a 32-byte message (including null
237/// // terminator).
238///
239/// // DATA
240/// char d_buffer[32];
241///
242/// // FRIEND
243/// friend class my_MessageFactory;
244///
245/// // NOT IMPLEMENTED
246/// my_LargeMessage(const my_LargeMessage&);
247/// my_LargeMessage& operator=(const my_LargeMessage&);
248///
249/// // PRIVATE CREATORS
250/// my_LargeMessage(const char *msg, int length)
251/// {
252/// assert(length <= 31);
253///
254/// bsl::memcpy(d_buffer, msg, length);
255/// d_buffer[length] = '\0';
256/// }
257///
258/// virtual ~my_LargeMessage() {}
259/// // Destroy this object.
260///
261/// // PRIVATE ACCESSORS
262/// virtual const char *getMessage()
263/// {
264/// return d_buffer;
265/// }
266/// };
267///
268/// class my_GenericMessage : public my_Message {
269/// // This class represents a generic message.
270///
271/// // DATA
272/// char *d_buffer;
273///
274/// // FRIEND
275/// friend class my_MessageFactory;
276///
277/// // NOT IMPLEMENTED
278/// my_GenericMessage(const my_GenericMessage&);
279/// my_GenericMessage& operator=(const my_GenericMessage&);
280///
281/// // PRIVATE CREATORS
282/// my_GenericMessage(char *msg) : d_buffer(msg)
283/// {
284/// }
285///
286/// virtual ~my_GenericMessage() {}
287/// // Destroy this object.
288///
289/// // PRIVATE ACCESSORS
290/// virtual const char *getMessage()
291/// {
292/// return d_buffer;
293/// }
294/// };
295/// @endcode
296/// Then we define our factory class, `my_MessageFactory`, as follows:
297/// @code
298/// class my_MessageFactory {
299/// // This class implements an efficient message factory that builds and
300/// // returns messages. The life-time of the messages created by this
301/// // factory is the same as this factory.
302///
303/// // DATA
304/// bdlma::ConcurrentMultipool d_multipool; // multipool used to supply
305/// // memory
306///
307/// private:
308/// // Not implemented:
309/// my_MessageFactory(const my_MessageFactory&);
310///
311/// public:
312/// // CREATORS
313/// my_MessageFactory(bslma::Allocator *basicAllocator = 0);
314/// // Create a message factory. Optionally specify a 'basicAllocator'
315/// // used to supply memory. If 'basicAllocator' is 0, the currently
316/// // installed default allocator is used.
317///
318/// ~my_MessageFactory();
319/// // Destroy this factory and reclaim all messages created by it.
320///
321/// // MANIPULATORS
322/// my_Message *createMessage(const char *data);
323/// // Create a message storing the specified 'data'. The behavior is
324/// // undefined unless 'data' is null-terminated.
325///
326/// void disposeAllMessages();
327/// // Dispose of all created messages.
328///
329/// void disposeMessage(my_Message *message);
330/// // Dispose of the specified 'message'. The behavior is undefined
331/// // unless 'message' was created by this factory.
332/// };
333/// @endcode
334/// The use of a multipool and the `release` method enables the
335/// `disposeAllMessages` method to quickly deallocate all memory blocks used to
336/// create messages:
337/// @code
338/// // MANIPULATORS
339/// inline
340/// void my_MessageFactory::disposeAllMessages()
341/// {
342/// d_multipool.release();
343/// }
344/// @endcode
345/// The multipool can also reuse deallocated memory. Once a message is
346/// destroyed by the `disposeMessage` method, memory allocated for that message
347/// is reclaimed by the multipool and can be used to create the next message
348/// having the same size:
349/// @code
350/// inline
351/// void my_MessageFactory::disposeMessage(my_Message *message)
352/// {
353/// d_multipool.deleteObject(message);
354/// }
355/// @endcode
356/// A multipool optimizes the allocation of memory by using
357/// dynamically-allocated buffers (also known as chunks) to supply memory. As
358/// each chunk can satisfy multiple memory block requests before requiring
359/// additional dynamic memory allocation, the number of dynamic allocation
360/// requests needed is greatly reduced.
361///
362/// For the number of pools managed by the multipool, we chose to use the
363/// implementation-defined default value instead of calculating and specifying a
364/// value. Note that if users want to specify the number of pools, the value
365/// can be calculated as the smallest `N` such that the following relationship
366/// holds:
367/// @code
368/// N > log2(sizeof(Object Type)) - 2
369/// @endcode
370/// Continuing on with the usage example:
371/// @code
372/// // CREATORS
373/// my_MessageFactory::my_MessageFactory(bslma::Allocator *basicAllocator)
374/// : d_multipool(basicAllocator)
375/// {
376/// }
377/// @endcode
378/// Note that in the destructor, all outstanding messages are reclaimed
379/// automatically when `d_multipool` is destroyed:
380/// @code
381/// my_MessageFactory::~my_MessageFactory()
382/// {
383/// }
384/// @endcode
385/// A `bdlma::ConcurrentMultipool` is ideal for allocating the different sized
386/// messages since repeated deallocations might be necessary (which renders a
387/// `bdlma::SequentialPool` unsuitable) and the sizes of these types are all
388/// different:
389/// @code
390/// // MANIPULATORS
391/// my_Message *my_MessageFactory::createMessage(const char *data)
392/// {
393/// enum { k_SMALL = 8, k_MEDIUM = 16, k_LARGE = 32 };
394///
395/// const int length = static_cast<int>(bsl::strlen(data));
396///
397/// if (length < k_SMALL) {
398/// return new(d_multipool.allocate(sizeof(my_SmallMessage)))
399/// my_SmallMessage(data, length); // RETURN
400/// }
401///
402/// if (length < k_MEDIUM) {
403/// return new(d_multipool.allocate(sizeof(my_MediumMessage)))
404/// my_MediumMessage(data, length); // RETURN
405/// }
406///
407/// if (length < k_LARGE) {
408/// return new(d_multipool.allocate(sizeof(my_LargeMessage)))
409/// my_LargeMessage(data, length); // RETURN
410/// }
411///
412/// char *buffer = (char *)d_multipool.allocate(length + 1);
413/// bsl::memcpy(buffer, data, length + 1);
414///
415/// return new(d_multipool.allocate(sizeof(my_GenericMessage)))
416/// my_GenericMessage(buffer);
417/// }
418/// @endcode
419///
420/// ### Example 2: Implementing an Allocator Using bdlma::ConcurrentMultipool {#bdlma_concurrentmultipool-example-2-implementing-an-allocator-using-bdlma-concurrentmultipool}
421///
422///
423/// `bslma::Allocator` is used throughout the interfaces of BDE components.
424/// Suppose we would like to create a multipool allocator,
425/// `my_MultipoolAllocator`, that allocates memory from multiple
426/// `bdlma::ConcurrentPool` objects in a similar fashion to
427/// `bdlma::ConcurrentMultipool`. This class can be used directly to implement
428/// such an allocator.
429///
430/// Note that the documentation for this class is simplified for this usage
431/// example. Please see @ref bdlmca_multipoolallocator for full documentation of a
432/// similar class.
433/// @code
434/// class my_MultipoolAllocator : public bslma::Allocator{
435/// // This class implements the 'bslma::Allocator' protocol to provide an
436/// // allocator that manages a set of memory pools, each dispensing memory
437/// // blocks of a unique size, with each successive pool's block size
438/// // being twice that of the previous one.
439///
440/// // DATA
441/// bdlma::ConcurrentMultipool d_multiPool; // memory manager for
442/// // allocated memory blocks
443///
444/// public:
445/// // CREATORS
446/// my_MultipoolAllocator(bslma::Allocator *basicAllocator = 0);
447/// // Create a multipool allocator. Optionally specify a
448/// // 'basicAllocator' used to supply memory. If 'basicAllocator' is
449/// // 0, the currently installed default allocator is used.
450///
451/// // ...
452///
453/// virtual ~my_MultipoolAllocator();
454/// // Destroy this multipool allocator. All memory allocated from
455/// // this memory pool is released.
456///
457/// // MANIPULATORS
458/// virtual void *allocate(bsls::Types::size_type size);
459/// // Return the address of a contiguous block of maximally-aligned
460/// // memory of (at least) the specified 'size' (in bytes). If 'size'
461/// // is 0, no memory is allocated and 0 is returned.
462///
463/// virtual void deallocate(void *address);
464/// // Relinquish the memory block at the specified 'address' back to
465/// // this multipool allocator for reuse. The behavior is undefined
466/// // unless 'address' is non-zero, was allocated by this multipool
467/// // allocator, and has not already been deallocated.
468/// };
469///
470/// // CREATORS
471/// inline
472/// my_MultipoolAllocator::my_MultipoolAllocator(
473/// bslma::Allocator *basicAllocator)
474/// : d_multiPool(basicAllocator)
475/// {
476/// }
477///
478/// my_MultipoolAllocator::~my_MultipoolAllocator()
479/// {
480/// }
481///
482/// // MANIPULATORS
483/// inline
484/// void *my_MultipoolAllocator::allocate(bsls::Types::size_type size)
485/// {
486/// return d_multiPool.allocate(size);
487/// }
488///
489/// inline
490/// void my_MultipoolAllocator::deallocate(void *address)
491/// {
492/// d_multiPool.deallocate(address);
493/// }
494/// @endcode
495/// @}
496/** @} */
497/** @} */
498
499/** @addtogroup bdl
500 * @{
501 */
502/** @addtogroup bdlma
503 * @{
504 */
505/** @addtogroup bdlma_concurrentmultipool
506 * @{
507 */
508
509#include <bdlscm_version.h>
510
512#include <bdlma_blocklist.h>
513
514#include <bslma_allocator.h>
515#include <bslma_deleterhelper.h>
516
517#include <bslmt_mutex.h>
518
519#include <bsls_alignmentutil.h>
520#include <bsls_blockgrowth.h>
521#include <bsls_types.h>
522
523
524namespace bdlma {
525
526class ConcurrentPool;
527
528 // =========================
529 // class ConcurrentMultipool
530 // =========================
531
532/// This class implements a memory manager that maintains a configurable
533/// number of `bdlma::Pool` objects, each dispensing memory blocks of a
534/// unique size. The `Pool` objects are placed in an array, with each
535/// successive pool managing memory blocks of size twice that of the
536/// previous pool. Each multipool allocation (deallocation) request
537/// allocates memory from (returns memory to) the internal pool having the
538/// smallest block size not less than the requested size, or, if no pool
539/// manages memory blocks of sufficient sized, from a separately managed
540/// list of memory blocks. Both the `release` method and the destructor of
541/// a `bdema::Multipool` release all memory currently allocated via the
542/// object.
543///
544/// See @ref bdlma_concurrentmultipool
546
547 // PRIVATE TYPES
548
549 /// This `struct` provides header information for each allocated memory
550 /// block. The header stores the index to the pool used for the memory
551 /// allocation.
552 struct Header {
553
554 union {
555 int d_poolIdx; // pool used for this memory
556 // block
557
559 d_dummy; // force maximum alignment
560 } d_header;
561 };
562
563 // DATA
564 ConcurrentPool *d_pools_p; // array of memory pools, each
565 // dispensing fixed-size memory blocks
566
567 int d_numPools; // number of memory pools
568
570 d_maxBlockSize; // largest memory block size; dispensed
571 // by the 'd_numPools - 1'th pool;
572 // always a power of 2
573
574 bdlma::BlockList d_blockList; // memory manager for "large" memory
575 // blocks.
576
577 bslmt::Mutex d_mutex; // synchronize data access
578
580 d_allocAdapter; // thread-safe adapter
581
582 private:
583 // NOT IMPLEMENTED
585 ConcurrentMultipool& operator=(const ConcurrentMultipool&);
586
587 private:
588 // PRIVATE MANIPULATORS
589
590 void initialize(bsls::BlockGrowth::Strategy growthStrategy,
591 int maxBlocksPerChunk);
592 void initialize(const bsls::BlockGrowth::Strategy *growthStrategyArray,
593 int maxBlocksPerChunk);
594 void initialize(bsls::BlockGrowth::Strategy growthStrategy,
595 const int *maxBlocksPerChunkArray);
596 /// Initialize this multipool with the specified `growthStrategy[Array]`
597 /// and `maxBlocksPerChunk[Array]`. If an array is used, each
598 /// individual `bdlma::Pool` maintained by this multipool is initialized
599 /// with the corresponding growth strategy or max blocks per chunk entry
600 /// within the array.
601 void initialize(const bsls::BlockGrowth::Strategy *growthStrategyArray,
602 const int *maxBlocksPerChunkArray);
603
604 // PRIVATE ACCESSORS
605
606 /// Return the index of the memory pool in this multipool for an
607 /// allocation request of the specified `size` (in bytes). Note that
608 /// the index of the memory pool managing memory blocks having the
609 /// minimum block size is 0.
610 int findPool(bsls::Types::size_type size) const;
611
612 public:
613 // CREATORS
614
615 explicit ConcurrentMultipool(bslma::Allocator *basicAllocator = 0);
617 bslma::Allocator *basicAllocator = 0);
619 bsls::BlockGrowth::Strategy growthStrategy,
620 bslma::Allocator *basicAllocator = 0);
622 bsls::BlockGrowth::Strategy growthStrategy,
623 bslma::Allocator *basicAllocator = 0);
624 /// Create a multipool memory manager. Optionally specify `numPools`,
625 /// indicating the number of internally created `Pool` objects; the
626 /// block size of the first pool is 8 bytes, with the block size of each
627 /// additional pool successively doubling. If `numPools` is not
628 /// specified, an implementation-defined number of pools `N` -- covering
629 /// memory blocks ranging in size from `2^3 = 8` to `2^(N+2)` -- are
630 /// created. Optionally specify a `growthStrategy` indicating whether
631 /// the number of blocks allocated at once for every internally created
632 /// `Pool` should be either fixed or grow geometrically, starting with
633 /// 1. If `growthStrategy` is not specified, the allocation strategy
634 /// for each internally created `Pool` object is geometric, starting
635 /// from 1. If `numPools` is specified, optionally specify a
636 /// `maxBlocksPerChunk`, indicating the maximum number of blocks to be
637 /// allocated at once when a pool must be replenished. If
638 /// `maxBlocksPerChunk` is not specified, an implementation-defined
639 /// value is used. Optionally specify a `basicAllocator` used to supply
640 /// memory. If `basicAllocator` is 0, the currently installed default
641 /// allocator is used. Memory allocation (and deallocation) requests
642 /// will be satisfied using the internally maintained pool managing
643 /// memory blocks of the smallest size not less than the requested size,
644 /// or directly from the underlying allocator (supplied at
645 /// construction), if no internally pool managing memory block of
646 /// sufficient size exists. The behavior is undefined unless
647 /// `1 <= numPools` and `1 <= maxBlocksPerChunk`. Note that, on
648 /// platforms where `8 < bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT`,
649 /// excess memory may be allocated for pools managing smaller blocks.
650 /// Also note that `maxBlocksPerChunk` need not be an integral power of
651 /// 2; if geometric growth would exceed the maximum value, the chunk
652 /// size is capped at that value).
654 bsls::BlockGrowth::Strategy growthStrategy,
655 int maxBlocksPerChunk,
656 bslma::Allocator *basicAllocator = 0);
657
659 const bsls::BlockGrowth::Strategy *growthStrategyArray,
660 bslma::Allocator *basicAllocator = 0);
662 const bsls::BlockGrowth::Strategy *growthStrategyArray,
663 int maxBlocksPerChunk,
664 bslma::Allocator *basicAllocator = 0);
666 bsls::BlockGrowth::Strategy growthStrategy,
667 const int *maxBlocksPerChunkArray,
668 bslma::Allocator *basicAllocator = 0);
669 /// Create a multipool memory manager having the specified `numPools`,
670 /// indicating the number of internally created `Pool` objects; the
671 /// block size of the first pool is 8 bytes, with the block size of each
672 /// additional pool successively doubling. Optionally specify a
673 /// `growthStrategy` indicating whether the number of blocks allocated
674 /// at once for every internally created `Pool` should be either fixed
675 /// or grow geometrically, starting with 1. If `growthStrategy` is not
676 /// specified, optionally specify `growthStrategyArray`, indicating the
677 /// strategies for each individual `Pool` created by this object. If
678 /// neither `growthStrategy` nor `growthStrategyArray` are specified,
679 /// the allocation strategy for each internally created `Pool` object
680 /// will grow geometrically, starting from 1. Optionally specify a
681 /// `maxBlocksPerChunk`, indicating the maximum number of blocks to be
682 /// allocated at once when a pool must be replenished. If
683 /// `maxBlocksPerChunk` is not specified, optionally specify
684 /// `maxBlocksPerChunkArray`, indicating the maximum number of blocks to
685 /// allocate at once for each individually created `Pool` object. If
686 /// neither `maxBlocksPerChunk` nor `maxBlocksPerChunkArray` are
687 /// specified, an implementation-defined value is used. Optionally
688 /// specify a `basicAllocator` used to supply memory. If
689 /// `basicAllocator` is 0, the currently installed default allocator is
690 /// used. Memory allocation (and deallocation) requests will be
691 /// satisfied using the internally maintained pool managing memory
692 /// blocks of the smallest size not less than the requested size, or
693 /// directly from the underlying allocator (supplied at construction),
694 /// if no internally pool managing memory block of sufficient size
695 /// exists. The behavior is undefined unless `1 <= numPools`,
696 /// `growthStrategyArray` has at least `numPools` strategies,
697 /// `1 <= maxBlocksPerChunk` and `maxBlocksPerChunkArray` have at least
698 /// `numPools` positive values. Note that, on platforms where
699 /// `8 < bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT`, excess memory may be
700 /// allocated for pools managing smaller blocks. Also note that the
701 /// maximum need not be an integral power of 2; if geometric growth
702 /// would exceed a maximum value, the chunk size is capped at that
703 /// value).
705 int numPools,
706 const bsls::BlockGrowth::Strategy *growthStrategyArray,
707 const int *maxBlocksPerChunkArray,
708 bslma::Allocator *basicAllocator = 0);
709
710 /// Destroy this multipool. All memory allocated from this memory pool
711 /// is released.
713
714 // MANIPULATORS
715
716 /// Return the address of a contiguous block of maximally-aligned memory
717 /// of (at least) the specified `size` (in bytes). If
718 /// `size > maxPooledBlockSize()`, the memory allocation is managed
719 /// directly by the underlying allocator, and will not be pooled, but
720 /// will be deallocated when the `release` method is called, or when
721 /// this object is destroyed. If `size` is 0, no memory is allocated
722 /// and 0 is returned.
724
725 /// Relinquish the memory block at the specified `address` back to this
726 /// multipool object for reuse. The behavior is undefined unless
727 /// `address` is non-zero, was allocated by this multipool object, and
728 /// has not already been deallocated.
729 void deallocate(void *address);
730
731 /// Destroy the specified `object` based on its dynamic type and then
732 /// use this multipool object to deallocate its memory footprint. This
733 /// method has no effect if `object` is 0. The behavior is undefined
734 /// unless `object`, when cast appropriately to `void *`, was allocated
735 /// using this multipool object and has not already been deallocated.
736 /// Note that `dynamic_cast<void *>(object)` is applied if `TYPE` is
737 /// polymorphic, and `static_cast<void *>(object)` is applied otherwise.
738 template <class TYPE>
739 void deleteObject(const TYPE *object);
740
741 /// Destroy the specified `object` and then use this multipool to
742 /// deallocate its memory footprint. This method has no effect if
743 /// `object` is 0. The behavior is undefined unless `object` is **not** a
744 /// secondary base class pointer (i.e., the address is (numerically) the
745 /// same as when it was originally dispensed by this multipool), was
746 /// allocated using this multipool, and has not already been
747 /// deallocated.
748 template <class TYPE>
749 void deleteObjectRaw(const TYPE *object);
750
751 /// Relinquish all memory currently allocated via this multipool object.
752 void release();
753
754 /// Reserve memory from this multipool to satisfy memory requests for at
755 /// least the specified `numBlocks` having the specified `size` (in
756 /// bytes) before the pool replenishes. If `size` is 0, this method has
757 /// no effect. The behavior is undefined unless
758 /// `size <= maxPooledBlockSize()` and `0 <= numBlocks`.
759 void reserveCapacity(bsls::Types::size_type size, int numBlocks);
760
761 // ACCESSORS
762
763 /// Return the number of pools managed by this multipool object.
764 int numPools() const;
765
766 /// Return the maximum size of memory blocks that are pooled by this
767 /// multipool object. Note that the maximum value is defined as:
768 /// @code
769 /// 2 ^ (numPools + 2)
770 /// @endcode
771 /// where `numPools` is either specified at construction, or an
772 /// implementation-defined value.
774
775
776 // Aspects
777
778 /// Return the allocator used by this object to allocate memory. Note
779 /// that this allocator can not be used to deallocate memory
780 /// allocated through this pool.
782};
783
784// ============================================================================
785// INLINE DEFINITIONS
786// ============================================================================
787
788 // -------------------------
789 // class ConcurrentMultipool
790 // -------------------------
791
792// MANIPULATORS
793template <class TYPE>
794inline
795void ConcurrentMultipool::deleteObject(const TYPE *object)
796{
798}
799
800template <class TYPE>
801inline
803{
805}
806
807// ACCESSORS
808inline
810{
811 return d_numPools;
812}
813
814inline
816{
817 return d_maxBlockSize;
818}
819
820// Aspects
821
822inline
824{
825 return d_blockList.allocator();
826}
827
828} // close package namespace
829
830
831#endif
832
833// ----------------------------------------------------------------------------
834// Copyright 2016 Bloomberg Finance L.P.
835//
836// Licensed under the Apache License, Version 2.0 (the "License");
837// you may not use this file except in compliance with the License.
838// You may obtain a copy of the License at
839//
840// http://www.apache.org/licenses/LICENSE-2.0
841//
842// Unless required by applicable law or agreed to in writing, software
843// distributed under the License is distributed on an "AS IS" BASIS,
844// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
845// See the License for the specific language governing permissions and
846// limitations under the License.
847// ----------------------------- END-OF-FILE ----------------------------------
848
849/** @} */
850/** @} */
851/** @} */
Definition bdlma_blocklist.h:235
bslma::Allocator * allocator() const
Return the allocator used by this object to allocate memory.
Definition bdlma_blocklist.h:321
Definition bdlma_concurrentallocatoradapter.h:288
Definition bdlma_concurrentmultipool.h:545
int numPools() const
Return the number of pools managed by this multipool object.
Definition bdlma_concurrentmultipool.h:809
bslma::Allocator * allocator() const
Definition bdlma_concurrentmultipool.h:823
void deallocate(void *address)
void * allocate(bsls::Types::size_type size)
ConcurrentMultipool(bsls::BlockGrowth::Strategy growthStrategy, bslma::Allocator *basicAllocator=0)
ConcurrentMultipool(int numPools, bslma::Allocator *basicAllocator=0)
void deleteObject(const TYPE *object)
Definition bdlma_concurrentmultipool.h:795
ConcurrentMultipool(bslma::Allocator *basicAllocator=0)
void deleteObjectRaw(const TYPE *object)
Definition bdlma_concurrentmultipool.h:802
void reserveCapacity(bsls::Types::size_type size, int numBlocks)
ConcurrentMultipool(int numPools, const bsls::BlockGrowth::Strategy *growthStrategyArray, const int *maxBlocksPerChunkArray, bslma::Allocator *basicAllocator=0)
ConcurrentMultipool(int numPools, bsls::BlockGrowth::Strategy growthStrategy, const int *maxBlocksPerChunkArray, bslma::Allocator *basicAllocator=0)
bsls::Types::size_type maxPooledBlockSize() const
Definition bdlma_concurrentmultipool.h:815
ConcurrentMultipool(int numPools, bsls::BlockGrowth::Strategy growthStrategy, bslma::Allocator *basicAllocator=0)
ConcurrentMultipool(int numPools, const bsls::BlockGrowth::Strategy *growthStrategyArray, bslma::Allocator *basicAllocator=0)
ConcurrentMultipool(int numPools, const bsls::BlockGrowth::Strategy *growthStrategyArray, int maxBlocksPerChunk, bslma::Allocator *basicAllocator=0)
void release()
Relinquish all memory currently allocated via this multipool object.
ConcurrentMultipool(int numPools, bsls::BlockGrowth::Strategy growthStrategy, int maxBlocksPerChunk, bslma::Allocator *basicAllocator=0)
Definition bdlma_concurrentpool.h:332
Definition bslma_allocator.h:457
Definition bslmt_mutex.h:315
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlma_alignedallocator.h:276
static void deleteObject(const TYPE *object, ALLOCATOR *allocator)
Definition bslma_deleterhelper.h:196
static void deleteObjectRaw(const TYPE *object, ALLOCATOR *allocator)
Definition bslma_deleterhelper.h:217
AlignmentToType< BSLS_MAX_ALIGNMENT >::Type MaxAlignedType
Definition bsls_alignmentutil.h:282
Strategy
Definition bsls_blockgrowth.h:169
std::size_t size_type
Definition bsls_types.h:124