What
Read-only accessors (empty(), full(), size()) acquire a full std::mutex lock. For single-producer single-consumer (SPSC) scenarios, all mutex overhead is unnecessary and introduces contention where none should exist.
Current Behavior
// circular_buffer.h:55-67
bool empty() const { std::lock_guard<std::mutex> lock(mutex_); return head_ == tail_; }
bool full() const { std::lock_guard<std::mutex> lock(mutex_); return ((tail_ + 1) % capacity_) == head_; }
size_t size() const { std::lock_guard<std::mutex> lock(mutex_); /* ... */ }
Expected Behavior
An SPSC variant uses std::atomic<std::size_t> for head/tail indices with std::memory_order_acquire/release, eliminating all mutex overhead in single-producer single-consumer scenarios.
Why
- Mutex acquisition on every
empty()/full()/size() call adds unnecessary latency in SPSC use cases
- Lock-free SPSC queues are a well-established pattern with proven performance benefits
- The existing mutex-based version should remain as the default for multi-producer multi-consumer (MPMC) safety
Where
- File:
include/kcenon/common/utils/circular_buffer.h:55-67
How
Technical Approach
- Create an SPSC variant (e.g.,
spsc_circular_buffer<T>) using std::atomic<std::size_t> for head_ and tail_ indices
- Use
std::memory_order_acquire for loads and std::memory_order_release for stores
- Keep the existing
circular_buffer<T> unchanged as the default thread-safe (MPMC) version
- Optionally provide a common interface/base for both variants
Acceptance Criteria
What
Read-only accessors (
empty(),full(),size()) acquire a fullstd::mutexlock. For single-producer single-consumer (SPSC) scenarios, all mutex overhead is unnecessary and introduces contention where none should exist.Current Behavior
Expected Behavior
An SPSC variant uses
std::atomic<std::size_t>for head/tail indices withstd::memory_order_acquire/release, eliminating all mutex overhead in single-producer single-consumer scenarios.Why
empty()/full()/size()call adds unnecessary latency in SPSC use casesWhere
include/kcenon/common/utils/circular_buffer.h:55-67How
Technical Approach
spsc_circular_buffer<T>) usingstd::atomic<std::size_t>forhead_andtail_indicesstd::memory_order_acquirefor loads andstd::memory_order_releasefor storescircular_buffer<T>unchanged as the default thread-safe (MPMC) versionAcceptance Criteria
circular_buffer<T>) remains unchanged