55[ ![ Platform] ( https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg )] ( #platform-support )
66[ ![ Header-only] ( https://img.shields.io/badge/header--only-yes-brightgreen.svg )] ( #installation )
77[ ![ Lock-free] ( https://img.shields.io/badge/concurrency-lock--free-orange.svg )] ( #architecture )
8+ [ ![ CI] ( https://github.com/SlickQuant/slick_object_pool/actions/workflows/ci.yml/badge.svg )] ( https://github.com/SlickQuant/slick_object_pool/actions/workflows/ci.yml )
9+ [ ![ GitHub release] ( https://img.shields.io/github/v/release/SlickQuant/slick_object_pool )] ( https://github.com/SlickQuant/slick_object_pool/releases )
810
911A high-performance, lock-free object pool for C++20 with multi-threading support. Designed for real-time systems, game engines, high-frequency trading, and any application requiring predictable, low-latency object allocation.
1012
@@ -15,15 +17,13 @@ A high-performance, lock-free object pool for C++20 with multi-threading support
1517 - [ Features] ( #features )
1618 - [ 🚀 Performance] ( #-performance )
1719 - [ 🔧 Architecture] ( #-architecture )
18- - [ 🌐 Shared Memory] ( #-shared-memory )
1920 - [ ⚡ Use Cases] ( #-use-cases )
2021 - [ Quick Start] ( #quick-start )
2122 - [ Installation] ( #installation )
2223 - [ Header-Only Integration] ( #header-only-integration )
2324 - [ CMake Integration] ( #cmake-integration )
2425 - [ Usage Examples] ( #usage-examples )
2526 - [ Basic Usage] ( #basic-usage )
26- - [ Shared Memory (Inter-Process)] ( #shared-memory-inter-process )
2727 - [ Multi-Threaded Usage] ( #multi-threaded-usage )
2828 - [ Architecture] ( #architecture )
2929 - [ Lock-Free MPMC Design] ( #lock-free-mpmc-design )
@@ -49,8 +49,6 @@ A high-performance, lock-free object pool for C++20 with multi-threading support
4949 - [ Best Practices] ( #best-practices )
5050 - [ Pool Size Selection] ( #pool-size-selection )
5151 - [ Pool Exhaustion Handling] ( #pool-exhaustion-handling )
52- - [ Shared Memory Lifecycle] ( #shared-memory-lifecycle )
53- - [ Type Design for Shared Memory] ( #type-design-for-shared-memory )
5452 - [ Limitations] ( #limitations )
5553 - [ FAQ] ( #faq )
5654 - [ Contributing] ( #contributing )
@@ -74,18 +72,11 @@ A high-performance, lock-free object pool for C++20 with multi-threading support
7472- ** Type-safe** - Static assertions ensure compatible types
7573- ** Cross-platform** - Windows, Linux, macOS, and Unix-like systems
7674
77- ### 🌐 Shared Memory
78- - ** Inter-process communication** - Share pools across multiple processes
79- - ** Zero-copy** - Direct memory access without serialization
80- - ** Automatic synchronization** - Lock-free coordination between processes
81- - ** Lifecycle management** - Automatic cleanup on process termination
82-
8375### ⚡ Use Cases
8476- Real-time systems (robotics, industrial control)
8577- Game engines (entity management, particle systems)
8678- High-frequency trading systems
8779- Network servers (connection pooling, buffer management)
88- - Multi-process data pipelines
8980- Any scenario requiring predictable allocation performance
9081
9182## Quick Start
@@ -192,63 +183,6 @@ int main() {
192183}
193184```
194185
195- ### Shared Memory (Inter-Process)
196-
197- **Process 1: Create and populate shared pool**
198-
199- ```cpp
200- #include <slick/object_pool.h>
201-
202- struct SharedData {
203- int64_t timestamp;
204- double price;
205- };
206-
207- int main() {
208- // Create shared memory pool (512 objects, power of 2)
209- slick::ObjectPool<SharedData> pool(512, "market_data_pool");
210-
211- // Pool is automatically initialized and ready to use
212- for (int i = 0; i < 100; ++i) {
213- SharedData* data = pool.allocate_object();
214- data->timestamp = get_current_time();
215- data->price = get_market_price();
216-
217- // Process data...
218-
219- pool.free_object(data);
220- }
221-
222- return 0;
223- }
224- ```
225-
226- ** Process 2: Attach to existing shared pool**
227-
228- ``` cpp
229- #include < slick/object_pool.h>
230-
231- struct SharedData {
232- int64_t timestamp;
233- double price;
234- };
235-
236- int main() {
237- // Attach to existing shared pool
238- slick::ObjectPool<SharedData > pool("market_data_pool");
239-
240- // Use the shared pool
241- SharedData* data = pool.allocate_object();
242-
243- // Process shared data...
244- std::cout << "Price: " << data->price << std::endl;
245-
246- pool.free_object(data);
247-
248- return 0;
249- }
250- ```
251-
252186### Multi-Threaded Usage
253187
254188```cpp
@@ -276,7 +210,7 @@ void worker_thread(slick::ObjectPool<WorkItem>& pool, int thread_id) {
276210}
277211
278212int main() {
279- // Create shared pool (must be power of 2)
213+ // Create pool (must be power of 2)
280214 slick::ObjectPool<WorkItem> pool(2048);
281215
282216 // Launch multiple producer/consumer threads
@@ -330,23 +264,12 @@ Cache Lines 2+ - Shared data:
330264
331265### Memory Layout
332266
333- ** Local Memory Mode:**
334267```
335268ObjectPool instance
336269 ├─ Heap: buffer_[size_] (actual objects)
337270 ├─ Heap: control_[size_] (slot metadata)
338271 ├─ Heap: free_objects_[size_] (free list)
339- └─ Stack: reserved_, consumed_ (local atomics)
340- ```
341-
342- ** Shared Memory Mode:**
343- ```
344- Shared Memory Segment "pool_name"
345- ├─ [0-63]: reserved_ + size_ (Producer cache line)
346- ├─ [64-127]: consumed_ (Consumer cache line)
347- ├─ [128+]: control_[size_] (Slot metadata)
348- ├─ [N+]: buffer_[size_] (Object storage)
349- └─ [M+]: free_objects_[size_] (Free list)
272+ └─ Stack: reserved_, consumed_ (atomics)
350273```
351274
352275## Performance
@@ -365,13 +288,13 @@ Tested on: Intel Xeon E5-2680 v4 @ 2.4GHz, 256GB RAM, Linux 5.15
365288
366289### Comparison with Alternatives
367290
368- | Implementation | Allocation Latency | Thread Safety | Shared Memory |
369- | ----------------| -------------------| ---------------| --------------- |
370- | slick_object_pool | ~ 12-35 ns | Lock-free MPMC | ✅ Yes |
371- | std::allocator | ~ 50-200 ns | Thread-local | ❌ No |
372- | boost::pool | ~ 20-40 ns | Mutex-based | ❌ No |
373- | tcmalloc | ~ 30-60 ns | Thread-local | ❌ No |
374- | jemalloc | ~ 25-50 ns | Thread-local | ❌ No |
291+ | Implementation | Allocation Latency | Thread Safety |
292+ | ----------------| -------------------| ---------------|
293+ | slick_object_pool | ~ 12-35 ns | Lock-free |
294+ | std::allocator | ~ 50-200 ns | Thread-local |
295+ | boost::pool | ~ 20-40 ns | Mutex-based |
296+ | tcmalloc | ~ 30-60 ns | Thread-local |
297+ | jemalloc | ~ 25-50 ns | Thread-local |
375298
376299* Note: Benchmarks are system-dependent. Run your own tests for production use.*
377300
@@ -381,19 +304,11 @@ Tested on: Intel Xeon E5-2680 v4 @ 2.4GHz, 256GB RAM, Linux 5.15
381304
382305``` cpp
383306// Create pool in local memory
384- ObjectPool (uint32_t size, const char* shm_name = nullptr);
385-
386- // Open existing shared memory pool
387- ObjectPool(const char* shm_name);
307+ ObjectPool (uint32_t size);
388308```
389309
390310**Parameters:**
391311- `size`: Number of objects in pool (must be power of 2)
392- - `shm_name`: Name for shared memory segment (nullptr for local memory)
393-
394- **Throws:**
395- - `std::runtime_error`: If shared memory allocation fails
396- - `std::invalid_argument`: If size is not power of 2 (assertion in debug)
397312
398313### Methods
399314
@@ -410,9 +325,7 @@ void free_object(T* obj);
410325Returns an object to the pool if it belongs to the pool, otherwise deletes it.
411326
412327```cpp
413- // Query methods
414- bool own_buffer() const noexcept; // Is this the pool owner?
415- bool use_shm() const noexcept; // Using shared memory?
328+ // Query method
416329constexpr uint32_t size() const noexcept; // Pool size
417330```
418331
@@ -421,31 +334,29 @@ constexpr uint32_t size() const noexcept; // Pool size
421334Objects stored in the pool must satisfy:
422335
423336``` cpp
424- static_assert (std::is_trivially_copyable_v<T>);
425- static_assert (std::is_standard_layout_v<T>);
337+ static_assert (std::is_default_constructible_v<T>);
426338```
427339
428340** Valid types:**
429341- POD types (int, float, etc.)
430- - Structs with trivial copy/move
431- - Arrays of valid types
342+ - std::string, std::vector, and other standard containers
343+ - Structs with default constructors
344+ - Classes with default constructors
432345
433346** Invalid types:**
434- - Types with virtual functions
435- - Types with user-defined copy constructors
436- - Types containing pointers to process-local memory (for shared memory mode)
437- - std::string, std::vector (contains pointers)
347+ - Types without default constructors
348+ - Types with deleted default constructors
438349
439350## Platform Support
440351
441- | Platform | Status | API Used |
442- | ----------| --------| ---------- |
443- | Windows (MSVC) | ✅ Tested | File Mapping API |
444- | Windows (MinGW) | ✅ Tested | File Mapping API |
445- | Linux | ✅ Tested | POSIX shm_open/mmap |
446- | macOS | ✅ Tested | POSIX shm_open/mmap |
447- | FreeBSD | ⚠️ Should work | POSIX shm_open/mmap |
448- | Unix-like | ⚠️ Should work | POSIX shm_open/mmap |
352+ | Platform | Status |
353+ | ----------| --------|
354+ | Windows (MSVC) | ✅ Tested |
355+ | Windows (MinGW) | ✅ Tested |
356+ | Linux | ✅ Tested |
357+ | macOS | ✅ Tested |
358+ | FreeBSD | ⚠️ Should work |
359+ | Unix-like | ⚠️ Should work |
449360
450361## Requirements
451362
@@ -545,7 +456,6 @@ sudo cmake --install .
545456- ✅ ** Multiple producers** can call ` allocate_object() ` concurrently
546457- ✅ ** Multiple consumers** can call ` free_object() ` concurrently
547458- ✅ ** Mixed operations** (allocate + free) are safe
548- - ✅ ** Shared memory** pools are safe across processes
549459- ❌ ** reset()** is NOT thread-safe (use when no other threads are active)
550460
551461### Memory Ordering
@@ -584,76 +494,51 @@ T* obj = pool.allocate_object(); // May return heap-allocated object
584494pool.free_object(obj); // Works for pool or heap objects
585495```
586496
587- ### Shared Memory Lifecycle
588-
589- ``` cpp
590- // Process 1: Creates pool
591- {
592- slick::ObjectPool<T> owner(1024, "my_pool");
593- // Pool exists in shared memory
594- // ...
595- } // Pool destroyed when owner exits
596-
597- // Process 2: Must handle pool disappearing
598- try {
599- slick::ObjectPool<T> client("my_pool");
600- // Use pool...
601- } catch (const std::runtime_error& e) {
602- // Pool doesn't exist or was deleted
603- }
604- ```
605-
606- ### Type Design for Shared Memory
497+ ### Type Design
607498
608499``` cpp
609- // ✅ Good: POD struct
610- struct GoodType {
500+ // ✅ Good: Simple POD struct
501+ struct SimpleType {
611502 int id;
612503 double values[ 10] ;
613504 char name[ 32] ;
614505};
615506
616- // ❌ Bad: Contains pointers
617- struct BadType {
507+ // ✅ Good: Types with STL containers
508+ struct ComplexType {
618509 int id;
619- std::string name; // Contains pointer!
620- std::vector<double > v; // Contains pointer!
510+ std::string name; // OK!
511+ std::vector<double > v; // OK!
512+ };
513+
514+ // ❌ Bad: No default constructor
515+ struct BadType {
516+ BadType(int x) : value(x) {} // No default constructor
517+ int value;
621518};
622519
623- // ✅ Workaround: Fixed-size arrays
520+ // ✅ Fix: Add default constructor
624521struct FixedType {
625- int id;
626- char name[ 32] ;
627- double values[ 10] ;
628- size_t value_count;
522+ FixedType() = default; // Default constructor
523+ FixedType(int x) : value(x) {}
524+ int value = 0;
629525};
630526```
631527
632528## Limitations
633529
6345301. **Pool size must be power of 2** - Required for efficient bitwise indexing
635- 2. **Type must be trivially copyable ** - Required for shared memory safety
531+ 2. **Type must be default constructible ** - Required for pool initialization
6365323. **No automatic resize** - Pool size is fixed at construction
637- 4. **Shared memory persistence** - Pool persists until owner process exits or calls destructor
638- 5. **No memory reclamation** - Objects returned to pool are reused, not freed
639- 6. **Platform-specific shared memory** - Windows and POSIX implementations differ
533+ 4. **No memory reclamation** - Objects returned to pool are reused, not freed
640534
641535## FAQ
642536
643537**Q: What happens when the pool is exhausted?**
644538A: `allocate_object()` automatically allocates from heap. `free_object()` detects and deletes heap-allocated objects.
645539
646540**Q: Can I use std::string or std::vector in pooled objects?**
647- A: No, for shared memory mode. These types contain pointers to process-local memory. Use fixed-size arrays instead.
648-
649- **Q: How do I know if I'm using shared memory or local memory?**
650- A: Call `pool.use_shm()` to check.
651-
652- **Q: Can multiple processes create the same shared pool?**
653- A: Yes, the first process becomes the owner. Others attach to the existing pool.
654-
655- **Q: What happens if the owner process crashes?**
656- A: On POSIX: Pool persists until explicitly unlinked. On Windows: Pool is automatically cleaned up.
541+ A: Yes! The pool works with any default constructible type, including std::string, std::vector, and other standard containers.
657542
658543**Q: Is the pool real-time safe?**
659544A: Operations are lock-free but not wait-free. Allocation may fail and fall back to heap allocation.
0 commit comments