BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_concurrentpoolallocator.h
Go to the documentation of this file.
1/// @file bdlma_concurrentpoolallocator.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_concurrentpoolallocator.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_CONCURRENTPOOLALLOCATOR
9#define INCLUDED_BDLMA_CONCURRENTPOOLALLOCATOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlma_concurrentpoolallocator bdlma_concurrentpoolallocator
15/// @brief Provide thread-safe memory-pooling allocator of fixed-size blocks.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlma
19/// @{
20/// @addtogroup bdlma_concurrentpoolallocator
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlma_concurrentpoolallocator-purpose"> Purpose</a>
25/// * <a href="#bdlma_concurrentpoolallocator-classes"> Classes </a>
26/// * <a href="#bdlma_concurrentpoolallocator-description"> Description </a>
27/// * <a href="#bdlma_concurrentpoolallocator-protocol-hierarchy"> Protocol Hierarchy </a>
28/// * <a href="#bdlma_concurrentpoolallocator-usage"> Usage </a>
29/// * <a href="#bdlma_concurrentpoolallocator-example-1-uniform-sized-allocations"> Example 1: Uniform Sized Allocations </a>
30/// * <a href="#bdlma_concurrentpoolallocator-example-2-variable-allocation-size"> Example 2: Variable Allocation Size </a>
31///
32/// # Purpose {#bdlma_concurrentpoolallocator-purpose}
33/// Provide thread-safe memory-pooling allocator of fixed-size blocks.
34///
35/// # Classes {#bdlma_concurrentpoolallocator-classes}
36///
37/// - bdlma::ConcurrentPoolAllocator: thread-safe allocator of pooled blocks
38///
39/// # Description {#bdlma_concurrentpoolallocator-description}
40/// This component defines a class,
41/// `bdlma::ConcurrentPoolAllocator`, that implements the `bslma::Allocator`
42/// protocol and provides a thread-safe allocator of pooled memory blocks of
43/// uniform size (the "pooled size"). The pooled size is either (1) configured
44/// at construction, or (2) equal to the size of the first block allocated
45/// through the allocator. All of the allocation requests of sizes up to the
46/// pooled size are satisfied with blocks from the underlying pool. All
47/// requests of sizes larger than the pooled size will be satisfied through the
48/// external allocator (the allocator supplied at construction, or the default
49/// allocator if no allocator was provided).
50///
51/// ## Protocol Hierarchy {#bdlma_concurrentpoolallocator-protocol-hierarchy}
52///
53///
54/// The interface hierarchy (defined by direct public inheritance) of
55/// `bdlma::ConcurrentPoolAllocator` is as follows:
56/// @code
57/// ,-------------------.
58/// ( bdlma::ConcurrentPoolAllocator )
59/// `-------------------'
60/// | ctor/dtor
61/// | objectSize
62/// V
63/// ,----------------.
64/// ( bslma::Allocator )
65/// `----------------'
66/// allocate
67/// deallocate
68/// @endcode
69/// `bdlma::ConcurrentPoolAllocator` provides a concrete, thread-safe
70/// implementation of the `bslma::Allocator` protocol.
71///
72/// ## Usage {#bdlma_concurrentpoolallocator-usage}
73///
74///
75/// The `bdlma::ConcurrentPoolAllocator` is intended to be used in either of the
76/// following two cases.
77///
78/// The first case is where frequent allocation and deallocation of memory
79/// occurs through the `bslma::Allocator` protocol and all of the allocated
80/// blocks have the same size. In this case, the size of blocks to pool is
81/// determined the first time `allocate` is called and need not be specified at
82/// construction.
83///
84/// The second case is where frequent allocation and deallocation of memory
85/// occurs through the `bslma::Allocator` protocol, most of the allocations have
86/// similar sizes, and a likely maximum for the largest allocation is known at
87/// the time of construction.
88///
89/// ### Example 1: Uniform Sized Allocations {#bdlma_concurrentpoolallocator-example-1-uniform-sized-allocations}
90///
91///
92/// The following example illustrates the use of
93/// `bdlma::ConcurrentPoolAllocator` when all allocations are of uniform size.
94/// A `bdlma::ConcurrentPoolAllocator` is used in the implementation of a "work
95/// queue" where each "item" enqueued by a producer thread is of identical size.
96/// Concurrently, a consumer dequeues each work item when it becomes available,
97/// verifies the content (a sequence number in ASCII), and deallocates the work
98/// item. The concurrent allocations and deallocations are valid because
99/// `bdlma::ConcurrentPoolAllocator` is thread-safe.
100///
101/// First, an abstract of the example will be given with focus and commentary on
102/// the relevant details of `bdlma::ConcurrentPoolAllocator`. Details
103/// pertaining to queue management, thread creation, thread synchronization,
104/// etc., can be seen in the full listing at the end of this example.
105///
106/// The parent thread creates the `bdlma::ConcurrentPoolAllocator` and work
107/// queue by the statements:
108/// @code
109/// bdlma::ConcurrentPoolAllocator poolAlloc;
110/// my1_WorkQueue queue(&poolAlloc);
111/// @endcode
112/// Note that since the default constructor is used to create `poolAlloc`, the
113/// pooled size has not yet been fixed.
114///
115/// The work queue is defined by the following data structures.
116/// @code
117/// struct my1_WorkItem {
118/// // DATA
119/// char *d_item; // represents work to perform
120/// };
121///
122/// struct my1_WorkQueue {
123/// // DATA
124/// bsl::list<my1_WorkItem> d_queue; // queue of work requests
125/// bslmt::Mutex d_mx; // protects the shared queue
126/// bslmt::Condition d_cv; // signals existence of new work
127/// bslma::Allocator *d_alloc_p; // pooled allocator
128///
129/// // CREATORS
130/// explicit my1_WorkQueue(bslma::Allocator *basicAllocator = 0)
131/// : d_alloc_p(bslma::Default::allocator(basicAllocator))
132/// {
133/// }
134/// };
135/// @endcode
136/// The producer and consumer threads are given the address of the work queue as
137/// their sole argument. Here, the producer allocates a work item, initializes
138/// it with a sequence number in ASCII, enqueues it, and signals its presence to
139/// the consumer thread. This action is done 50 times, and then a 51st, empty
140/// work item is added to inform the consumer of the end of the queue. The
141/// first allocation of a work item (100 bytes) fixes the pooled size. Each
142/// subsequent allocation is that same size (100 bytes). The producer's actions
143/// are shown below:
144/// @code
145/// extern "C"
146/// void *my1_producer(void *arg)
147/// {
148/// my1_WorkQueue *queue = (my1_WorkQueue *)arg;
149///
150/// for (int i = 0; i < 50; ++i) {
151/// char b[100];
152/// bsl::sprintf(b, "%d", i);
153/// int len = static_cast<int>(bsl::strlen(b));
154///
155/// my1_WorkItem request;
156///
157/// // Fixed allocation size sufficient for content.
158///
159/// request.d_item = (char *)queue->d_alloc_p->allocate(100);
160///
161/// bsl::memcpy(request.d_item, b, len+1);
162///
163/// // Enqueue item and signal any waiting threads.
164/// // ...
165/// }
166///
167/// // Add empty item.
168/// // ...
169///
170/// return queue;
171/// }
172/// @endcode
173/// When the consumer thread finds that the queue is not empty it dequeues the
174/// item, verifies its content (a sequence number in ASCII), returns the work
175/// item to the pool, and checks for the next item. If the queue is empty, the
176/// consumer blocks until signaled by the producer. An empty work item
177/// indicates that the producer will send no more items, so the consumer exits.
178/// The consumer's actions are shown below:
179/// @code
180/// extern "C"
181/// void *my1_consumer(void *arg)
182/// {
183/// my1_WorkQueue *queue = (my1_WorkQueue *)arg;
184///
185/// for (int i = 0; ; ++i) {
186///
187/// // Block until work item on queue.
188/// // ...
189///
190/// // Dequeue item.
191/// // ...
192///
193/// // Break when end-of-work item received.
194/// // ...
195///
196/// char b[100];
197/// bsl::sprintf(b, "%d", i);
198/// assert(bsl::strcmp(b, item.d_item) == 0); // check content
199///
200/// queue->d_alloc_p->deallocate(item.d_item); // deallocate
201/// }
202///
203/// return 0;
204/// }
205/// @endcode
206/// A complete listing of the example's structures and functions follows:
207/// @code
208/// struct my1_WorkItem {
209/// // DATA
210/// char *d_item; // represents work to perform
211/// };
212///
213/// struct my1_WorkQueue {
214/// // DATA
215/// bsl::list<my1_WorkItem> d_queue; // queue of work requests
216/// bslmt::Mutex d_mx; // protects the shared queue
217/// bslmt::Condition d_cv; // signals existence of new work
218/// bslma::Allocator *d_alloc_p; // pooled allocator
219///
220/// private:
221/// // Not implemented:
222/// my1_WorkQueue(const my1_WorkQueue&);
223///
224/// public:
225/// // CREATORS
226/// explicit my1_WorkQueue(bslma::Allocator *basicAllocator = 0)
227/// : d_alloc_p(bslma::Default::allocator(basicAllocator))
228/// {
229/// }
230/// };
231///
232/// extern "C" void *my1_producer(void *arg)
233/// {
234/// my1_WorkQueue *queue = (my1_WorkQueue *)arg;
235///
236/// for (int i = 0; i < 50; ++i) {
237///
238/// char b[100];
239/// bsl::sprintf(b, "%d", i);
240/// int len = static_cast<int>(bsl::strlen(b));
241///
242/// my1_WorkItem request;
243/// request.d_item = (char *)queue->d_alloc_p->allocate(100);
244/// bsl::memcpy(request.d_item, b, len+1);
245///
246/// if (veryVerbose) {
247/// // Assume thread-safe implementations of 'cout' and 'endl'
248/// // exist (named 'MTCOUT' and 'MTENDL', respectively).
249///
250/// MTCOUT << "Enqueuing " << request.d_item << MTENDL;
251/// }
252///
253/// queue->d_mx.lock();
254/// queue->d_queue.push_back(request);
255/// queue->d_mx.unlock();
256/// queue->d_cv.signal();
257/// }
258///
259/// my1_WorkItem request;
260/// request.d_item = 0;
261///
262/// queue->d_mx.lock();
263/// queue->d_queue.push_back(request);
264/// queue->d_mx.unlock();
265/// queue->d_cv.signal();
266///
267/// return queue;
268/// }
269///
270/// extern "C" void *my1_consumer(void *arg)
271/// {
272/// my1_WorkQueue *queue = (my1_WorkQueue *)arg;
273///
274/// for (int i = 0; ; ++i) {
275///
276/// queue->d_mx.lock();
277/// while (0 == queue->d_queue.size()) {
278/// queue->d_cv.wait(&queue->d_mx);
279/// }
280///
281/// my1_WorkItem item = queue->d_queue.front();
282/// queue->d_queue.pop_front();
283/// queue->d_mx.unlock();
284///
285/// if (0 == item.d_item) {
286/// break;
287/// }
288///
289/// // Process the work requests.
290/// if (veryVerbose) {
291/// // Assume thread-safe implementations of 'cout' and 'endl'
292/// // exist (named 'MTCOUT' and 'MTENDL', respectively).
293///
294/// MTCOUT << "Processing " << item.d_item << MTENDL;
295/// }
296///
297/// char b[100];
298/// bsl::sprintf(b, "%d", i);
299/// assert(bsl::strcmp(b, item.d_item) == 0);
300///
301/// queue->d_alloc_p->deallocate(item.d_item);
302/// }
303///
304/// return 0;
305/// }
306/// @endcode
307/// In the application `main`:
308/// @code
309/// {
310/// bdlma::ConcurrentPoolAllocator poolAlloc;
311/// my1_WorkQueue queue(&poolAlloc);
312///
313/// bslmt::ThreadAttributes attributes;
314///
315/// bslmt::ThreadUtil::Handle producerHandle;
316/// int status = bslmt::ThreadUtil::create(&producerHandle,
317/// attributes,
318/// &my1_producer,
319/// &queue);
320/// assert(0 == status);
321///
322/// bslmt::ThreadUtil::Handle consumerHandle;
323/// status = bslmt::ThreadUtil::create(&consumerHandle,
324/// attributes,
325/// &my1_consumer,
326/// &queue);
327/// assert(0 == status);
328/// status = bslmt::ThreadUtil::join(consumerHandle);
329/// assert(0 == status);
330/// status = bslmt::ThreadUtil::join(producerHandle);
331/// assert(0 == status);
332/// }
333/// @endcode
334///
335/// ### Example 2: Variable Allocation Size {#bdlma_concurrentpoolallocator-example-2-variable-allocation-size}
336///
337///
338/// The following example illustrates the use of
339/// `bdlma::ConcurrentPoolAllocator` when allocations are of varying size. A
340/// `bdlma::ConcurrentPoolAllocator` is used in the implementation of a "work
341/// queue" where each "item" enqueued by a producer thread varies in size, but
342/// all items are smaller than a known maximum. Concurrently, a consumer thread
343/// dequeues each work item when it is available, verifies its content (a
344/// sequence number in ASCII), and deallocates the work item. The concurrent
345/// allocations and deallocations are valid because
346/// `bdlma::ConcurrentPoolAllocator` is thread-safe.
347///
348/// First, an abstract of the example will be given with focus and commentary on
349/// the relevant details of `bdlma::ConcurrentPoolAllocator`. Details
350/// pertaining to queue management, thread creation, thread synchronization,
351/// etc., can be seen in the full listing at the end of this example.
352///
353/// The parent thread creates the `bdlma::ConcurrentPoolAllocator` and work
354/// queue by the statements:
355/// @code
356/// bdlma::ConcurrentPoolAllocator poolAlloc(100);
357/// my1_WorkQueue queue(&poolAlloc);
358/// @endcode
359/// Note that the pooled size (100) is specified in the construction of
360/// `poolAlloc`. Any requests in excess of that size will be satisfied by
361/// implicit calls to the default allocator, not from the underlying pool.
362///
363/// The work queue is defined by the following data structures.
364/// @code
365/// struct my2_WorkItem {
366/// // DATA
367/// char *d_item; // represents work to perform
368/// };
369///
370/// struct my2_WorkQueue {
371/// // DATA
372/// bsl::list<my2_WorkItem> d_queue; // queue of work requests
373/// bslmt::Mutex d_mx; // protects the shared queue
374/// bslmt::Condition d_cv; // signals existence of new work
375/// bslma::Allocator *d_alloc_p; // pooled allocator
376///
377/// // CREATORS
378/// explicit my2_WorkQueue(bslma::Allocator *basicAllocator = 0)
379/// : d_queue(basic_Allocator)
380/// , d_alloc_p(bslma::Default::allocator(basic_Allocator))
381/// {
382/// }
383/// };
384/// @endcode
385/// In this example (unlike Example 1), the given allocator is used not only for
386/// the work items, but is also passed to the constructor of `d_queue` so that
387/// it also serves memory for the operations of `bsl::list<my2_WorkItem>`.
388///
389/// The producer and consumer threads are given the address of the work queue as
390/// their sole argument. Here, the producer allocates a work item, initializes
391/// it with a sequence number in ASCII, enqueues it, and signals its presence to
392/// the consumer thread. The action is done 50 times, and then a 51st, empty
393/// work item is added to inform the consumer of the end of the queue. In this
394/// example, each work item is sized to match the length of its contents, the
395/// sequence number in ASCII. The producer's actions are shown below:
396/// @code
397/// extern "C" void *my2_producer(void *arg)
398/// {
399/// my2_WorkQueue *queue = (my2_WorkQueue *)arg;
400///
401/// for (int i = 0; i < 50; ++i) {
402///
403/// char b[100];
404/// bsl::sprintf(b, "%d", i);
405/// int len = static_cast<int>(bsl::strlen(b));
406///
407/// my2_WorkItem request;
408///
409/// // Allocate item to exactly match space needed for content.
410///
411/// request.d_item = (char *)queue->d_alloc_p->allocate(len+1);
412///
413/// bsl::memcpy(request.d_item, b, len+1);
414///
415/// // Enqueue item and signal any waiting threads.
416/// // ...
417/// }
418///
419/// // Add empty item.
420/// // ...
421///
422/// return queue;
423/// }
424/// @endcode
425/// The actions of this consumer thread are essentially the same as those of the
426/// consumer thread in Example 1.
427///
428/// When the consumer thread finds that the queue is not empty, it dequeues the
429/// item, verifies its content (a sequence number in ASCII), returns the work
430/// item to the pool, and checks for the next item. If the queue is empty, the
431/// consumer blocks until signaled by the producer. An empty work item
432/// indicates that the producer will send no more items, so the consumer exits.
433/// The consumer's actions are shown below.
434/// @code
435/// extern "C" void *my2_consumer(void *arg)
436/// {
437/// my2_WorkQueue *queue = (my2_WorkQueue *)arg;
438///
439/// while (int i = 0; ; ++i) {
440///
441/// // Block until work item on queue.
442/// // ...
443///
444/// // Deque item.
445/// // ...
446///
447/// // Break when end-of-work item received.
448/// // ...
449///
450/// char b[100];
451/// bsl::sprintf(b, "%d", i);
452/// assert(bsl::strcmp(b, item.d_item) == 0); // verify content
453///
454/// queue->d_alloc_p->deallocate(item.d_item); // deallocate
455/// }
456///
457/// return 0;
458/// }
459/// @endcode
460/// A complete listing of the example's structures and functions follows:
461/// @code
462/// struct my2_WorkItem {
463/// // DATA
464/// char *d_item; // represents work to perform
465/// };
466///
467/// struct my2_WorkQueue {
468/// // DATA
469/// bsl::list<my2_WorkItem> d_queue; // queue of work requests
470/// bslmt::Mutex d_mx; // protects the shared queue
471/// bslmt::Condition d_cv; // signals existence of new work
472/// bslma::Allocator *d_alloc_p; // pooled allocator
473///
474/// private:
475/// // Not implemented:
476/// my2_WorkQueue(const my2_WorkQueue&);
477///
478/// public:
479/// // CREATORS
480/// explicit my2_WorkQueue(bslma::Allocator *basicAllocator = 0)
481/// : d_queue(basicAllocator)
482/// , d_alloc_p(basicAllocator)
483/// {
484/// }
485/// };
486///
487/// extern "C" void *my2_producer(void *arg)
488/// {
489/// my2_WorkQueue *queue = (my2_WorkQueue *)arg;
490///
491/// for (int i = 0; i < 50; ++i) {
492///
493/// char b[100];
494/// bsl::sprintf(b, "%d", i);
495/// int len = static_cast<int>(bsl::strlen(b));
496///
497/// my2_WorkItem request;
498/// request.d_item = (char *)queue->d_alloc_p->allocate(len+1);
499/// bsl::memcpy(request.d_item, b, len+1);
500///
501/// if (veryVerbose) {
502/// // Assume thread-safe implementations of 'cout' and 'endl'
503/// // exist (named 'MTCOUT' and 'MTENDL', respectively).
504///
505/// MTCOUT << "Enqueuing " << request.d_item << MTENDL;
506/// }
507///
508/// queue->d_mx.lock();
509/// queue->d_queue.push_back(request);
510/// queue->d_mx.unlock();
511/// queue->d_cv.signal();
512/// }
513///
514/// my2_WorkItem request;
515/// request.d_item = 0;
516///
517/// queue->d_mx.lock();
518/// queue->d_queue.push_back(request);
519/// queue->d_mx.unlock();
520/// queue->d_cv.signal();
521///
522/// return queue;
523/// }
524///
525/// extern "C" void *my2_consumer(void *arg)
526/// {
527/// my2_WorkQueue *queue = (my2_WorkQueue *)arg;
528///
529/// for (int i = 0; ; ++i) {
530///
531/// queue->d_mx.lock();
532/// while (0 == queue->d_queue.size()) {
533/// queue->d_cv.wait(&queue->d_mx);
534/// }
535///
536/// my2_WorkItem item = queue->d_queue.front();
537/// queue->d_queue.pop_front();
538/// queue->d_mx.unlock();
539///
540/// if (0 == item.d_item) {
541/// break;
542/// }
543///
544/// // Process the work requests.
545/// if (veryVerbose) {
546/// // Assume thread-safe implementations of 'cout' and 'endl'
547/// // exist (named 'MTCOUT' and 'MTENDL', respectively).
548///
549/// MTCOUT << "Processing " << item.d_item << MTENDL;
550/// }
551///
552/// char b[100];
553/// bsl::sprintf(b, "%d", i);
554/// assert(bsl::strcmp(b, item.d_item) == 0);
555///
556/// queue->d_alloc_p->deallocate(item.d_item);
557/// }
558///
559/// return 0;
560/// }
561/// @endcode
562/// In the application's `main`:
563/// @code
564/// {
565/// bdlma::ConcurrentPoolAllocator poolAlloc(100);
566/// my2_WorkQueue queue(&poolAlloc);
567///
568/// bslmt::ThreadAttributes attributes;
569///
570/// bslmt::ThreadUtil::Handle producerHandle;
571/// int status = bslmt::ThreadUtil::create(&producerHandle,
572/// attributes,
573/// &my2_producer,
574/// &queue);
575/// assert(0 == status);
576///
577/// bslmt::ThreadUtil::Handle consumerHandle;
578/// status = bslmt::ThreadUtil::create(&consumerHandle,
579/// attributes,
580/// &my2_consumer,
581/// &queue);
582/// assert(0 == status);
583/// status = bslmt::ThreadUtil::join(consumerHandle);
584/// assert(0 == status);
585/// status = bslmt::ThreadUtil::join(producerHandle);
586/// assert(0 == status);
587/// }
588/// @endcode
589/// @}
590/** @} */
591/** @} */
592
593/** @addtogroup bdl
594 * @{
595 */
596/** @addtogroup bdlma
597 * @{
598 */
599/** @addtogroup bdlma_concurrentpoolallocator
600 * @{
601 */
602
603#include <bdlscm_version.h>
604
605#include <bdlma_concurrentpool.h>
606
607#include <bslma_allocator.h>
608
609#include <bsls_alignmentutil.h>
610#include <bsls_atomic.h>
611#include <bsls_blockgrowth.h>
612#include <bsls_keyword.h>
613#include <bsls_objectbuffer.h>
614#include <bsls_types.h>
615
616
617namespace bdlma {
618
619 // =============================
620 // class ConcurrentPoolAllocator
621 // =============================
622
623/// This class implements the `bslma::Allocator` protocol to provide an
624/// allocator that manages pooled memory blocks of some uniform size,
625/// specified either at construction, or at the first invocation of the
626/// `allocate` method. This allocator maintains an internal linked list of
627/// free memory blocks, and dispenses one block for each `allocate` method
628/// invocation. When a memory block is deallocated, it is returned to the
629/// free list for potential reuse.
630///
631/// This class guarantees thread-safety while allocating or releasing
632/// memory.
633///
634/// See @ref bdlma_concurrentpoolallocator
636
637 public:
638 // PUBLIC TYPES
639 typedef bsls::Types::size_type size_type; // type for block size
640
641 private:
642 // PRIVATE TYPES
643 enum {
644 k_MAGIC_NUMBER = 0x111902, // magic number that is inserted in header
645 // of items that are allocated from the
646 // underlying pool
647
648 k_UNINITIALIZED = 0, // pool not yet initialized
649
650 k_INITIALIZED = 1, // pool is initialized
651
652 k_INITIALIZING = -1 // pool initialization in progress
653 };
654
655 /// Leading header on each allocated memory block. If the memory block
656 /// is allocated from the pool, `d_magicNumber` is set to
657 /// `k_MAGIC_NUMBER`. Otherwise, memory is allocated from the external
658 /// allocator supplied at construction, and `d_magicNumber` is set to 0.
659 union Header {
660
661 int d_magicNumber; // allocation source
662 // and sanity check
663
664 bsls::AlignmentUtil::MaxAlignedType d_dummy; // forces alignment
665 };
666
667 // DATA
668 bsls::AtomicInt d_initialized; // initialization state indicator
669
671 d_pool; // buffer used to hold the 'Pool'
672 // (initialization occurs when the pooled
673 // memory block size first becomes known)
674
675 size_type d_blockSize; // block size
676
678 d_growthStrategy;
679 // growth strategy of the chunk size
680
681 int d_maxBlocksPerChunk;
682 // max chunk size (in blocks-per-chunk)
683
684 bslma::Allocator *d_allocator_p; // basic allocator, held but not owned
685
686 private:
687 // NOT IMPLEMENTED
688 ConcurrentPoolAllocator(const ConcurrentPoolAllocator&);
689 ConcurrentPoolAllocator& operator=(const ConcurrentPoolAllocator&);
690
691 public:
692 // CREATORS
693
694 explicit
696 explicit
698 bslma::Allocator *basicAllocator = 0);
699 /// Create a pool allocator that returns blocks of contiguous memory of
700 /// uniform size for each `allocate` method invocation, where the size
701 /// is determined by the first invocation of `allocate`. Optionally
702 /// specify a `growthStrategy` used to control the growth of internal
703 /// memory chunks (from which memory blocks are dispensed). If
704 /// `growthStrategy` is not specified, geometric growth is used. If
705 /// `growthStrategy` is specified, optionally specify a
706 /// `maxBlocksPerChunk`, indicating the maximum number of blocks to be
707 /// allocated at once when the underlying pool must be replenished. If
708 /// `maxBlocksPerChunk` is not specified, an implementation-defined
709 /// value is used. If geometric growth is used, the chunk size grows
710 /// starting at the value returned by `blockSize`, doubling in size
711 /// until the size is exactly `blockSize() * maxBlocksPerChunk`. If
712 /// constant growth is used, the chunk size is always
713 /// `maxBlocksPerChunk`. Optionally specify a `basicAllocator` used to
714 /// supply memory. If `basicAllocator` is 0, the currently installed
715 /// default allocator is used. The behavior is undefined unless
716 /// `1 <= maxBlocksPerChunk`.
718 int maxBlocksPerChunk,
719 bslma::Allocator *basicAllocator = 0);
720
721 explicit
723 bslma::Allocator *basicAllocator = 0);
725 bsls::BlockGrowth::Strategy growthStrategy,
726 bslma::Allocator *basicAllocator = 0);
727 /// Create a pool allocator that returns blocks of contiguous memory of
728 /// the specified `blockSize` (in bytes) for each `allocate` method
729 /// invocation. Optionally specify a `growthStrategy` used to control
730 /// the growth of internal memory chunks (from which memory blocks are
731 /// dispensed). If `growthStrategy` is not specified, geometric growth
732 /// is used. If `blockSize` and `growthStrategy` are specified,
733 /// optionally specify a `maxBlocksPerChunk`, indicating the maximum
734 /// number of blocks to be allocated at once when the underlying pool
735 /// must be replenished. If `maxBlocksPerChunk` is not specified, an
736 /// implementation-defined value is used. If geometric growth is used,
737 /// the chunk size grows starting at `blockSize`, doubling in size until
738 /// the size is exactly `blockSize * maxBlocksPerChunk`. If constant
739 /// growth is used, the chunk size is always `maxBlocksPerChunk`.
740 /// Optionally specify a `basicAllocator` used to supply memory. If
741 /// `basicAllocator` is 0, the currently installed default allocator is
742 /// used. The behavior is undefined unless `1 <= maxBlocksPerChunk`.
744 bsls::BlockGrowth::Strategy growthStrategy,
745 int maxBlocksPerChunk,
746 bslma::Allocator *basicAllocator = 0);
747
748 /// Destroy this pool allocator.
750
751 // MANIPULATORS
752
753 /// Return a newly allocated block of memory of (at least) the specified
754 /// positive `size` (in bytes), and having alignment conforming to the
755 /// platform requirement for any object having `size` bytes. If `size`
756 /// is 0, a null pointer is returned with no effect. If the block size
757 /// is not supplied at construction, then the `size` specified in the
758 /// first call to this method fixes the block size. If `size` is
759 /// greater than the value returned by `blockSize`, the allocation
760 /// request will be satisfied directly by the external allocator
761 /// supplied at construction (or the default allocator, if no allocator
762 /// was supplied).
764
765 /// Return the memory at the specified `address` back to this allocator.
766 /// If `address` is 0, this method has no effect. The behavior is
767 /// undefined unless `address` was allocated using this allocator and
768 /// has not already been deallocated.
770
771 /// Relinquish all memory currently allocated through this pool
772 /// allocator.
773 void release();
774
775 /// Reserve memory from this pool allocator to satisfy memory requests
776 /// for at least the specified `numObjects` before the pool replenishes.
777 /// The behavior is undefined unless `0 <= numObjects`. Note that this
778 /// operation has no effect unless block size was supplied at
779 /// construction, or `allocate` was invoked.
780 void reserveCapacity(int numObjects);
781
782 // ACCESSORS
783
784 /// Return the size (in bytes) of the memory blocks allocated from this
785 /// allocator. Note that all blocks dispensed by this allocator have
786 /// the same size.
787 size_type blockSize() const;
788};
789
790// ============================================================================
791// INLINE DEFINITIONS
792// ============================================================================
793
794 // -----------------------------
795 // class ConcurrentPoolAllocator
796 // -----------------------------
797
798// MANIPULATORS
799inline
801{
802 if (d_initialized == k_INITIALIZED) {
803 d_pool.object().release();
804 }
805}
806
807inline
809{
810 if (d_initialized == k_INITIALIZED) {
811 d_pool.object().reserveCapacity(numObjects);
812 }
813}
814
815// ACCESSORS
816inline
818{
819 return d_blockSize;
820}
821
822} // close package namespace
823
824
825#endif
826
827// ----------------------------------------------------------------------------
828// Copyright 2015 Bloomberg Finance L.P.
829//
830// Licensed under the Apache License, Version 2.0 (the "License");
831// you may not use this file except in compliance with the License.
832// You may obtain a copy of the License at
833//
834// http://www.apache.org/licenses/LICENSE-2.0
835//
836// Unless required by applicable law or agreed to in writing, software
837// distributed under the License is distributed on an "AS IS" BASIS,
838// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
839// See the License for the specific language governing permissions and
840// limitations under the License.
841// ----------------------------- END-OF-FILE ----------------------------------
842
843/** @} */
844/** @} */
845/** @} */
Definition bdlma_concurrentpoolallocator.h:635
void reserveCapacity(int numObjects)
Definition bdlma_concurrentpoolallocator.h:808
ConcurrentPoolAllocator(bsls::BlockGrowth::Strategy growthStrategy, int maxBlocksPerChunk, bslma::Allocator *basicAllocator=0)
void deallocate(void *address) BSLS_KEYWORD_OVERRIDE
ConcurrentPoolAllocator(bsls::BlockGrowth::Strategy growthStrategy, bslma::Allocator *basicAllocator=0)
size_type blockSize() const
Definition bdlma_concurrentpoolallocator.h:817
ConcurrentPoolAllocator(size_type blockSize, bslma::Allocator *basicAllocator=0)
ConcurrentPoolAllocator(size_type blockSize, bsls::BlockGrowth::Strategy growthStrategy, int maxBlocksPerChunk, bslma::Allocator *basicAllocator=0)
bsls::Types::size_type size_type
Definition bdlma_concurrentpoolallocator.h:639
~ConcurrentPoolAllocator() BSLS_KEYWORD_OVERRIDE
Destroy this pool allocator.
ConcurrentPoolAllocator(bslma::Allocator *basicAllocator=0)
ConcurrentPoolAllocator(size_type blockSize, bsls::BlockGrowth::Strategy growthStrategy, bslma::Allocator *basicAllocator=0)
void release()
Definition bdlma_concurrentpoolallocator.h:800
void * allocate(size_type size) BSLS_KEYWORD_OVERRIDE
Definition bslma_allocator.h:457
Definition bsls_atomic.h:743
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition bdlma_alignedallocator.h:276
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
Definition bsls_objectbuffer.h:276
TYPE & object()
Definition bsls_objectbuffer.h:351