Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
kcenon::logger::memory::thread_local_object_pool< T > Class Template Reference

Thread-local cached object pool for improved multi-threaded performance. More...

#include <object_pool.h>

Collaboration diagram for kcenon::logger::memory::thread_local_object_pool< T >:
Collaboration graph

Classes

struct  config
 Configuration for thread-local object pool. More...
 
struct  statistics
 Statistics for monitoring pool performance. More...
 

Public Member Functions

 thread_local_object_pool (const config &cfg=config{})
 Construct thread-local object pool with configuration.
 
 ~thread_local_object_pool ()=default
 Destructor.
 
std::unique_ptr< T > acquire ()
 Get an object from the pool.
 
void release (std::unique_ptr< T > obj)
 Return an object to the pool.
 
statistics get_statistics () const
 Get pool statistics.
 
void clear ()
 Clear all objects from pool.
 

Private Member Functions

void initialize_pool ()
 Initialize pool with initial objects.
 

Static Private Member Functions

static std::vector< std::unique_ptr< T > > & get_local_cache ()
 Get thread-local cache.
 

Private Attributes

config config_
 
std::vector< std::unique_ptr< T > > global_pool_
 
std::mutex global_mutex_
 
std::atomic< size_t > global_size_ {0}
 
std::atomic< size_t > local_cache_hits_ {0}
 
std::atomic< size_t > global_pool_hits_ {0}
 
std::atomic< size_t > new_allocations_ {0}
 

Detailed Description

template<typename T>
class kcenon::logger::memory::thread_local_object_pool< T >

Thread-local cached object pool for improved multi-threaded performance.

Template Parameters
TThe type of objects to pool

This implementation uses thread-local caching to minimize lock contention in multi-threaded environments. Each thread maintains a small local cache of objects, only accessing the global pool when the local cache is empty or full.

Performance characteristics:

  • Single thread: Similar to object_pool
  • Multi-threaded: 2-5x better than object_pool due to reduced lock contention

Memory overhead:

  • Each thread uses up to local_cache_size * sizeof(T*) additional memory
  • Recommended local_cache_size: 16 (empirically optimal)
Since
1.1.0

Definition at line 169 of file object_pool.h.

Constructor & Destructor Documentation

◆ thread_local_object_pool()

template<typename T >
kcenon::logger::memory::thread_local_object_pool< T >::thread_local_object_pool ( const config & cfg = config{})
inlineexplicit

Construct thread-local object pool with configuration.

Parameters
cfgPool configuration

Definition at line 187 of file object_pool.h.

187 {})
188 : config_(cfg)
189 , global_size_(0) {
191 }
void initialize_pool()
Initialize pool with initial objects.

◆ ~thread_local_object_pool()

Destructor.

Member Function Documentation

◆ acquire()

template<typename T >
std::unique_ptr< T > kcenon::logger::memory::thread_local_object_pool< T >::acquire ( )
inline

Get an object from the pool.

Returns
Unique pointer to object

Attempts to acquire from thread-local cache first (no lock), then from global pool in batches (single lock), and creates new if needed.

Definition at line 205 of file object_pool.h.

205 {
206 // Step 1: Check thread-local cache first (no lock!)
207 auto& local_cache = get_local_cache();
208
209 if (!local_cache.empty()) {
210 local_cache_hits_.fetch_add(1, std::memory_order_relaxed);
211 auto obj = std::move(local_cache.back());
212 local_cache.pop_back();
213 return obj;
214 }
215
216 // Step 2: Fetch batch from global pool (lock once)
217 {
218 std::lock_guard<std::mutex> lock(global_mutex_);
219
220 // Batch size: half of local cache size
221 size_t batch_size = std::min(
223 global_pool_.size()
224 );
225
226 for (size_t i = 0; i < batch_size; ++i) {
227 if (!global_pool_.empty()) {
228 local_cache.push_back(std::move(global_pool_.back()));
229 global_pool_.pop_back();
230 }
231 }
232 }
233
234 // Step 3: Try local cache again after batch fetch
235 if (!local_cache.empty()) {
236 global_pool_hits_.fetch_add(1, std::memory_order_relaxed);
237 auto obj = std::move(local_cache.back());
238 local_cache.pop_back();
239 return obj;
240 }
241
242 // Step 4: Create new object if pool is empty
243 if (config_.allow_growth && global_size_.load(std::memory_order_relaxed) < config_.global_max) {
244 global_size_.fetch_add(1, std::memory_order_relaxed);
245 new_allocations_.fetch_add(1, std::memory_order_relaxed);
246 return std::make_unique<T>();
247 }
248
249 // Fallback: create temporary object even if limit reached
250 // (same behavior as original object_pool)
251 return std::make_unique<T>();
252 }
static std::vector< std::unique_ptr< T > > & get_local_cache()
Get thread-local cache.
std::vector< std::unique_ptr< T > > global_pool_
bool allow_growth
Allow pool to grow beyond initial size.

References kcenon::logger::memory::thread_local_object_pool< T >::config::allow_growth, kcenon::logger::memory::thread_local_object_pool< T >::config_, kcenon::logger::memory::thread_local_object_pool< T >::get_local_cache(), kcenon::logger::memory::thread_local_object_pool< T >::config::global_max, kcenon::logger::memory::thread_local_object_pool< T >::global_mutex_, kcenon::logger::memory::thread_local_object_pool< T >::global_pool_, kcenon::logger::memory::thread_local_object_pool< T >::global_pool_hits_, kcenon::logger::memory::thread_local_object_pool< T >::global_size_, kcenon::logger::memory::thread_local_object_pool< T >::local_cache_hits_, kcenon::logger::memory::thread_local_object_pool< T >::config::local_cache_size, and kcenon::logger::memory::thread_local_object_pool< T >::new_allocations_.

Here is the call graph for this function:

◆ clear()

template<typename T >
void kcenon::logger::memory::thread_local_object_pool< T >::clear ( )
inline

Clear all objects from pool.

Warning
This does not clear thread-local caches

Definition at line 326 of file object_pool.h.

326 {
327 std::lock_guard<std::mutex> lock(global_mutex_);
328 global_pool_.clear();
329 global_size_.store(0, std::memory_order_relaxed);
330 local_cache_hits_.store(0, std::memory_order_relaxed);
331 global_pool_hits_.store(0, std::memory_order_relaxed);
332 new_allocations_.store(0, std::memory_order_relaxed);
333 }

References kcenon::logger::memory::thread_local_object_pool< T >::global_mutex_, kcenon::logger::memory::thread_local_object_pool< T >::global_pool_, kcenon::logger::memory::thread_local_object_pool< T >::global_pool_hits_, kcenon::logger::memory::thread_local_object_pool< T >::global_size_, kcenon::logger::memory::thread_local_object_pool< T >::local_cache_hits_, and kcenon::logger::memory::thread_local_object_pool< T >::new_allocations_.

◆ get_local_cache()

template<typename T >
static std::vector< std::unique_ptr< T > > & kcenon::logger::memory::thread_local_object_pool< T >::get_local_cache ( )
inlinestaticprivate

Get thread-local cache.

Returns
Reference to thread-local cache vector

Definition at line 340 of file object_pool.h.

340 {
341 thread_local std::vector<std::unique_ptr<T>> cache;
342 return cache;
343 }

Referenced by kcenon::logger::memory::thread_local_object_pool< T >::acquire(), and kcenon::logger::memory::thread_local_object_pool< T >::release().

Here is the caller graph for this function:

◆ get_statistics()

template<typename T >
statistics kcenon::logger::memory::thread_local_object_pool< T >::get_statistics ( ) const
inline

◆ initialize_pool()

template<typename T >
void kcenon::logger::memory::thread_local_object_pool< T >::initialize_pool ( )
inlineprivate

◆ release()

template<typename T >
void kcenon::logger::memory::thread_local_object_pool< T >::release ( std::unique_ptr< T > obj)
inline

Return an object to the pool.

Parameters
objObject to return

Adds to thread-local cache if space available (no lock), otherwise transfers batch to global pool (single lock).

Definition at line 261 of file object_pool.h.

261 {
262 if (!obj) {
263 return;
264 }
265
266 // Step 1: Add to thread-local cache (no lock!)
267 auto& local_cache = get_local_cache();
268
269 if (local_cache.size() < config_.local_cache_size) {
270 local_cache.push_back(std::move(obj));
271 return;
272 }
273
274 // Step 2: Transfer batch to global pool when local cache is full
275 {
276 std::lock_guard<std::mutex> lock(global_mutex_);
277
278 // Move half of local cache to global
279 size_t transfer_count = config_.local_cache_size / 2;
280
281 for (size_t i = 0; i < transfer_count && !local_cache.empty(); ++i) {
282 if (global_pool_.size() < config_.global_max) {
283 global_pool_.push_back(std::move(local_cache.back()));
284 local_cache.pop_back();
285 }
286 }
287
288 // Add current object to global pool
289 if (global_pool_.size() < config_.global_max) {
290 global_pool_.push_back(std::move(obj));
291 }
292 // If exceeding max, object will be destroyed automatically
293 }
294 }

References kcenon::logger::memory::thread_local_object_pool< T >::config_, kcenon::logger::memory::thread_local_object_pool< T >::get_local_cache(), kcenon::logger::memory::thread_local_object_pool< T >::config::global_max, kcenon::logger::memory::thread_local_object_pool< T >::global_mutex_, kcenon::logger::memory::thread_local_object_pool< T >::global_pool_, and kcenon::logger::memory::thread_local_object_pool< T >::config::local_cache_size.

Here is the call graph for this function:

Member Data Documentation

◆ config_

◆ global_mutex_

◆ global_pool_

◆ global_pool_hits_

◆ global_size_

◆ local_cache_hits_

◆ new_allocations_


The documentation for this class was generated from the following file: