BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlma_concurrentfixedpool.h
Go to the documentation of this file.
1/// @file bdlma_concurrentfixedpool.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_concurrentfixedpool.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_CONCURRENTFIXEDPOOL
9#define INCLUDED_BDLMA_CONCURRENTFIXEDPOOL
10
11/// @defgroup bdlma_concurrentfixedpool bdlma_concurrentfixedpool
12/// @brief Provide thread-safe pool of limited # of blocks of uniform size.
13/// @addtogroup bdl
14/// @{
15/// @addtogroup bdlma
16/// @{
17/// @addtogroup bdlma_concurrentfixedpool
18/// @{
19///
20/// <h1> Outline </h1>
21/// * <a href="#bdlma_concurrentfixedpool-purpose"> Purpose</a>
22/// * <a href="#bdlma_concurrentfixedpool-classes"> Classes </a>
23/// * <a href="#bdlma_concurrentfixedpool-description"> Description </a>
24/// * <a href="#bdlma_concurrentfixedpool-usage"> Usage </a>
25/// * <a href="#bdlma_concurrentfixedpool-example-1-basic-usage"> Example 1: Basic Usage </a>
26///
27/// # Purpose {#bdlma_concurrentfixedpool-purpose}
28/// Provide thread-safe pool of limited # of blocks of uniform size.
29///
30/// # Classes {#bdlma_concurrentfixedpool-classes}
31///
32/// - bdlma::ConcurrentFixedPool: thread-safe pool of limited number of blocks
33///
34/// @see bdlma_concurrentpool
35///
36/// # Description {#bdlma_concurrentfixedpool-description}
37/// This component implements a *fully thread-safe* memory pool
38/// that allocates and manages a limited number (specified at construction) of
39/// memory blocks of some uniform size (also specified at construction). A
40/// `bdlma::ConcurrentFixedPool` constructed to manage up to `N` blocks also
41/// provides an association between the address of each block and an index in
42/// the range `[ 0 .. N - 1 ]`.
43///
44/// Other than this mapping between block and index, and the associated limit on
45/// the maximum number of blocks that may be simultaneously allocated, this
46/// component's semantics are identical to `bdlma::ConcurrentPool`. In
47/// particular, this component overloads global operator `new` in the same
48/// manner, and the behaviors of `release` and `reserveCapacity` are equivalent
49/// to the corresponding methods in `bdlma::ConcurrentPool`.
50///
51/// Like `bdlma::ConcurrentPool`, this component is intended to be used to
52/// implement *out-of-place* container classes that hold elements of uniform
53/// size.
54///
55/// ## Usage {#bdlma_concurrentfixedpool-usage}
56///
57///
58/// This section illustrates intended use of this component.
59///
60/// ### Example 1: Basic Usage {#bdlma_concurrentfixedpool-example-1-basic-usage}
61///
62///
63/// `bdlma::ConcurrentFixedPool` is intended to implement *out-of-place*
64/// container classes that hold up to a fixed number of elements, all of uniform
65/// size. Suppose we wish to implement a simple thread pool. We want the
66/// equivalent of a `bsl::deque<bsl::function<void(void)> >`. However, to
67/// minimize the time spent performing operations on this deque - which must be
68/// carried out under a lock - we instead store just pointers in the deque, and
69/// manage memory efficiently using `bdlma::ConcurrentFixedPool`.
70/// `bdlma::ConcurrentFixedPool` is fully thread-safe and does not require any
71/// additional synchronization.
72///
73/// The example below is just for the container portion of our simple thread
74/// pool. The implementation of the worker thread, and the requisite
75/// synchronization, are omitted for clarity.
76/// @code
77/// class my_JobQueue {
78///
79/// public:
80/// // PUBLIC TYPES
81/// typedef bsl::function<void(void)> Job;
82///
83/// private:
84/// // DATA
85/// bslmt::Mutex d_lock;
86/// bsl::deque<Job *> d_queue;
87/// bdlma::ConcurrentFixedPool d_pool;
88/// bslma::Allocator *d_allocator_p;
89///
90/// // Not implemented:
91/// my_JobQueue(const my_JobQueue&);
92///
93/// public:
94/// // CREATORS
95/// my_JobQueue(int maxJobs, bslma::Allocator *basicAllocator = 0);
96/// ~my_JobQueue();
97///
98/// // MANIPULATORS
99/// void enqueueJob(const Job& job);
100///
101/// int tryExecuteJob();
102/// };
103///
104/// my_JobQueue::my_JobQueue(int maxJobs, bslma::Allocator *basicAllocator)
105/// : d_queue(basicAllocator)
106/// , d_pool(sizeof(Job), maxJobs, basicAllocator)
107/// , d_allocator_p(bslma::Default::allocator(basicAllocator))
108/// {
109/// }
110///
111/// my_JobQueue::~my_JobQueue()
112/// {
113/// Job *jobPtr;
114/// while (!d_queue.empty()) {
115/// jobPtr = d_queue.front();
116/// jobPtr->~Job();
117/// d_queue.pop_front();
118/// }
119/// }
120///
121/// void my_JobQueue::enqueueJob(const Job& job)
122/// {
123/// Job *jobPtr = new (d_pool) Job(job, d_allocator_p);
124/// d_lock.lock();
125/// d_queue.push_back(jobPtr);
126/// d_lock.unlock();
127/// }
128///
129/// int my_JobQueue::tryExecuteJob()
130/// {
131/// d_lock.lock();
132/// if (d_queue.empty()) {
133/// d_lock.unlock();
134/// return -1; // RETURN
135/// }
136/// Job *jobPtr = d_queue.front();
137/// d_queue.pop_front();
138/// d_lock.unlock();
139/// (*jobPtr)();
140/// d_pool.deleteObject(jobPtr);
141/// return 0;
142/// }
143/// @endcode
144/// Note that in the destructor, there is no need to deallocate the individual
145/// job objects - the destructor of `bdlma::ConcurrentFixedPool` will release
146/// any remaining allocated memory. However, it *is* necessary to invoke the
147/// destructors of all these objects, as the destructor of
148/// `bdlma::ConcurrentFixedPool` will not do so.
149/// @}
150/** @} */
151/** @} */
152
153/** @addtogroup bdl
154 * @{
155 */
156/** @addtogroup bdlma
157 * @{
158 */
159/** @addtogroup bdlma_concurrentfixedpool
160 * @{
161 */
162
163#include <bdlscm_version.h>
164
165#include <bslmt_mutex.h>
166
167#include <bsls_atomic.h>
168
169#include <bdlma_pool.h>
170
171#include <bslma_allocator.h>
172#include <bslma_deleterhelper.h>
173
174#include <bsls_alignmentutil.h>
175#include <bsls_assert.h>
176
177#include <bsl_vector.h>
178#include <bsl_cstdlib.h>
179
180
181namespace bdlma {
182
183 // ===============================
184 // struct ConcurrentFixedPool_Node
185 // ===============================
186
187/// The component-private `struct` provides a header for blocks that are
188/// allocated from `ConcurrentFixedPool` objects.
189///
190/// See @ref bdlma_concurrentfixedpool
192
193 // DATA
194 unsigned d_next; // index of next free node when on free list; otherwise,
195 // index of this node itself adjusted with a generation
196 // count
197};
198
199 // =========================
200 // class ConcurrentFixedPool
201 // =========================
202
203/// This class implements a memory pool that allocates and manages up to a
204/// fixed number of memory blocks of some uniform size, with both the limit
205/// on the number of blocks and the block size specified at construction.
206///
207/// This class guarantees thread safety when allocating or releasing memory
208/// (but see the documentation for the `release` method).
209///
210/// See @ref bdlma_concurrentfixedpool
212
213 // PRIVATE TYPES
214 typedef ConcurrentFixedPool_Node Node; // type of memory block "header"
215
216 // DATA
217 bsls::AtomicInt d_freeList; // head of free list
218
219 const unsigned d_sizeMask; // mask corresponding to max size
220 // of pool; rounded up to power of
221 // 2
222
223 bsl::vector<Node *> d_nodes; // holds nodes currently being
224 // pooled; enables index <->
225 // address mapping
226
227 const int d_dataOffset; // offset (in bytes) to memory
228 // block within a 'Node'
229
230 const int d_nodeSize; // size of blocks pooled by
231 // 'd_nodePool'
232
233 bslmt::Mutex d_nodePoolMutex; // mutex for access to 'd_nodePool'
234
235 bdlma::Pool d_nodePool; // underlying memory pool
236
237 int d_numNodes; // number of nodes in 'd_nodes'
238 // that are currently being pooled
239
240 const int d_objectSize; // size of pooled objects as
241 // specified at construction
242
243 int d_backoffLevel; // determines amount of spinning
244 // when under contention
245
246 private:
247 // NOT IMPLEMENTED
249 ConcurrentFixedPool& operator=(const ConcurrentFixedPool&);
250
251 private:
252 // PRIVATE MANIPULATORS
253
254 /// Allocate a memory block of the `objectSize` specified at
255 /// construction from the underlying pool from which this fixed pool
256 /// obtains memory. Return the address of that block or 0 if this pool
257 /// is exhausted (i.e., `poolSize()` memory blocks have already been
258 /// allocated from this pool).
259 void *allocateNew();
260
261 public:
262 // CREATORS
263
264 /// Create a memory pool that returns memory of the specified
265 /// `objectSize` for each invocation of the `allocate` method.
266 /// Configure this pool to support allocation of up to the specified
267 /// `poolSize` number of memory blocks. The largest supported
268 /// `poolSize` is 33554431. Optionally specify a `basicAllocator` used
269 /// to supply memory. If `basicAllocator` is 0, the currently installed default allocator is used.
270 ///
271 /// \pre The behavior is undefined unless
272 /// `0 < objectSize`, `0 < poolSize`, and `0x1FFFFFF >= poolSize`.
274 int poolSize,
275 bslma::Allocator *basicAllocator = 0);
276
277 /// Destroy this object and release all associated memory.
279
280 // MANIPULATORS
281
282 /// Allocate a memory block of the `objectSize` specified at
283 /// construction. Return the address of that block or 0 if the pool is
284 /// exhausted (i.e., `poolSize()` memory blocks have already been
285 /// allocated from this pool).
286 void *allocate();
287
288 /// Deallocate the memory block at the specified `address` back to this
289 /// pool for reuse.
290 void deallocate(void *address);
291
292 /// Destroy the specified `object` based on its dynamic type and then
293 /// use this allocator to deallocate its memory footprint. Do nothing if `object` is 0.
294 ///
295 /// \pre The behavior is undefined unless `object`, when
296 /// cast appropriately to `void *`, was allocated using this allocator
297 /// and has not already been deallocated.
298 ///
299 /// \note Note that `dynamic_cast<void *>(object)` is applied if `TYPE` is polymorphic,
300 /// and `static_cast<void *>(object)` is applied otherwise.
301 template<class TYPE>
302 void deleteObject(const TYPE *object);
303
304 /// Destroy the specified `object` based on its static type and then use
305 /// this allocator to deallocate its memory footprint. Do nothing if `object` is 0.
306 ///
307 /// \pre The behavior is undefined if `object` is a
308 /// base-class pointer to a derived type, was not allocated using this
309 /// allocator, or has already been deallocated.
310 template <class TYPE>
311 void deleteObjectRaw(const TYPE *object);
312
313 /// Release all memory currently allocated through this object.
314 ///
315 /// \note Note that this method should only be invoked when it is known that no
316 /// blocks currently allocated through this pool will be used;
317 /// therefore, it is not safe to use this method if any other thread may
318 /// be concurrently allocating memory from this pool. Also note that
319 /// `release()` is intended to free all memory without regard to the
320 /// contents of that memory. Specifically, `release()` can *not* call
321 /// object destructors for any allocated objects, since it has no
322 /// knowledge of their type. If object destruction is required, use
323 /// `ConcurrentFixedPool::deleteObject()`.
324 void release();
325
326 /// Reserve memory from this pool to satisfy memory requests for at
327 /// least the specified `numObjects` before the pool replenishes.
328 ///
329 /// \pre The behavior is undefined unless `0 <= numObjects`. Return 0 on success
330 /// and the number of objects that could not be reserved otherwise.
331 ///
332 /// \note Note that this method fails if the number of memory blocks already
333 /// allocated plus `numObjects` exceeds `poolSize()`.
334 int reserveCapacity(int numObjects);
335
336 /// Configure this pool with the specified non-negative `backoffLevel`
337 /// that controls the amount of spinning that occurs when calls to this
338 /// pool encounter contention. Setting `backoffLevel` to 0 disables
339 /// spinning. Greater values of `backoffLevel` correspond to greater amounts of spinning.
340 ///
341 /// \pre The behavior is undefined unless `0 <= backoffLevel`.
342 ///
343 /// \note Note that both contention detection and
344 /// spinning strategy are implementation defined.
346
347 // ACCESSORS
348
349 /// Return the non-negative `backoffLevel` that controls the amount of
350 /// spinning that occurs when calls to this pool encounter contention.
351 int backoffLevel() const;
352
353 /// Return an index in the range from 0 to the maximum size of this pool
354 /// that uniquely identifies the memory block at the specified `address`.
355 ///
356 /// \pre The behavior is undefined unless `address` corresponds
357 /// to a memory block allocated from this pool.
358 int indexFromAddress(void *address) const;
359
360 /// Return the size of the memory blocks allocated from this object.
361 ///
362 /// \note Note that all blocks have the same size.
363 int objectSize() const;
364
365 /// Return the address of the memory block identified by the specified `index`.
366 ///
367 /// \pre The behavior is undefined unless the index has been
368 /// obtained through `indexFromAddress`.
369 void *addressFromIndex(int index) const;
370
371 /// Return the maximum size of this pool.
372 int poolSize() const;
373
374 // Aspects
375
376 /// Return the allocator used by this object to allocate memory.
377 ///
378 /// \note Note that this allocator can not be used to deallocate memory
379 /// allocated through this pool.
381};
382
383} // close package namespace
384
385
386// FREE OPERATORS
387
388/// Allocate memory of the specified `size` bytes from the specified `pool`,
389/// and return the address of the allocated memory.
390///
391/// \pre The behavior is undefined unless `size` is the same as the `objectSize` with which `pool` was constructed.
392///
393/// \note Note that an object may allocate additional
394/// memory internally within its constructor, requiring the allocator to be
395/// passed in as a constructor argument:
396/// @code
397/// my_Type *newMyType(bdlma::ConcurrentFixedPool *pool,
398/// bslma::Allocator *basicAllocator) {
399/// return new (*pool) my_Type(..., basicAllocator);
400/// }
401/// @endcode
402/// Note also that the analogous version of operator `delete` should not be
403/// called directly. Instead, this component provides a template member
404/// function `bdlma::ConcurrentFixedPool::deleteObject` parameterized by
405/// `TYPE` that performs the equivalent of the following:
406/// @code
407/// void deleteMyType(bdlma::ConcurrentFixedPool *pool, my_Type *t) {
408/// t->~my_Type();
409/// pool->deallocate(t);
410/// }
411/// @endcode
412inline
413void *operator new(bsl::size_t size,
414 BloombergLP::bdlma::ConcurrentFixedPool& pool);
415
416/// Use the specified `pool` to deallocate the memory at the specified `address`.
417///
418/// \pre The behavior is undefined unless `address` was allocated
419/// using `pool` and has not already been deallocated. This operator is
420/// supplied solely to allow the compiler to arrange for it to be called in
421/// case of an exception. Client code should not call it; use
422/// `bdlma::ConcurrentFixedPool::deleteObject()` instead.
423inline
424void operator delete(void *address,
425 BloombergLP::bdlma::ConcurrentFixedPool& pool);
426
427
428namespace bdlma {
429
430// ============================================================================
431// INLINE DEFINITIONS
432// ============================================================================
433
434 // -------------------------
435 // class ConcurrentFixedPool
436 // -------------------------
437
438// MANIPULATORS
439template<class TYPE>
440inline
441void ConcurrentFixedPool::deleteObject(const TYPE *object)
442{
444}
445
446template<class TYPE>
447inline
449{
451}
452
453inline
455{
456 d_backoffLevel = backoffLevel;
457}
458
459// ACCESSORS
460inline
462{
463 Node * node = const_cast<Node *>(d_nodes[index]);
464
465 BSLS_ASSERT(node);
466 return (char *)node + d_dataOffset;
467}
468
469inline
471{
472 return d_backoffLevel;
473}
474
475inline
477{
478 const Node * const node = (const Node *)(void *)
479 ((char *)address - d_dataOffset);
480 return (node->d_next & d_sizeMask) - 1;
481}
482
483inline
485{
486 return d_objectSize;
487}
488
489inline
491{
492 return static_cast<int>(d_nodes.size());
493}
494
495// Aspects
496
497inline
499{
500 return d_nodePool.allocator();
501}
502
503} // close package namespace
504
505
506inline
507void *operator new(bsl::size_t size,
508 BloombergLP::bdlma::ConcurrentFixedPool& pool)
509{
510 using namespace BloombergLP;
511 BSLS_ASSERT((int) size <= pool.objectSize()
514
515 (void)size; // suppress "unused parameter" warnings
516 return pool.allocate();
517}
518
519inline
520void operator delete(void *address,
521 BloombergLP::bdlma::ConcurrentFixedPool& pool)
522{
523 pool.deallocate(address);
524}
525
526#endif
527
528// ----------------------------------------------------------------------------
529// Copyright 2015 Bloomberg Finance L.P.
530//
531// Licensed under the Apache License, Version 2.0 (the "License");
532// you may not use this file except in compliance with the License.
533// You may obtain a copy of the License at
534//
535// http://www.apache.org/licenses/LICENSE-2.0
536//
537// Unless required by applicable law or agreed to in writing, software
538// distributed under the License is distributed on an "AS IS" BASIS,
539// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
540// See the License for the specific language governing permissions and
541// limitations under the License.
542// ----------------------------- END-OF-FILE ----------------------------------
543
544/** @} */
545/** @} */
546/** @} */
Definition bdlma_concurrentfixedpool.h:211
void * addressFromIndex(int index) const
Definition bdlma_concurrentfixedpool.h:461
int reserveCapacity(int numObjects)
bslma::Allocator * allocator() const
Definition bdlma_concurrentfixedpool.h:498
int objectSize() const
Definition bdlma_concurrentfixedpool.h:484
int backoffLevel() const
Definition bdlma_concurrentfixedpool.h:470
int indexFromAddress(void *address) const
Definition bdlma_concurrentfixedpool.h:476
void deleteObject(const TYPE *object)
Definition bdlma_concurrentfixedpool.h:441
int poolSize() const
Return the maximum size of this pool.
Definition bdlma_concurrentfixedpool.h:490
void setBackoffLevel(int backoffLevel)
Definition bdlma_concurrentfixedpool.h:454
~ConcurrentFixedPool()
Destroy this object and release all associated memory.
void deallocate(void *address)
void deleteObjectRaw(const TYPE *object)
Definition bdlma_concurrentfixedpool.h:448
ConcurrentFixedPool(int objectSize, int poolSize, bslma::Allocator *basicAllocator=0)
Definition bdlma_pool.h:338
bslma::Allocator * allocator() const
Definition bdlma_pool.h:639
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements in this vector.
Definition bslstl_vector.h:3019
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
Definition bslmt_mutex.h:317
Definition bsls_atomic.h:744
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
Definition bdlma_alignedallocator.h:278
Definition bdlma_concurrentfixedpool.h:191
unsigned d_next
Definition bdlma_concurrentfixedpool.h:194
static void deleteObject(const TYPE *object, ALLOCATOR *allocator)
Definition bslma_deleterhelper.h:204
static void deleteObjectRaw(const TYPE *object, ALLOCATOR *allocator)
Definition bslma_deleterhelper.h:225
static int calculateAlignmentFromSize(std::size_t size)
Definition bsls_alignmentutil.h:398