Skip to content

perf(circular-buffer): provide lock-free SPSC variant for single-producer single-consumer #485

Description

@kcenon

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

  1. Create an SPSC variant (e.g., spsc_circular_buffer<T>) using std::atomic<std::size_t> for head_ and tail_ indices
  2. Use std::memory_order_acquire for loads and std::memory_order_release for stores
  3. Keep the existing circular_buffer<T> unchanged as the default thread-safe (MPMC) version
  4. Optionally provide a common interface/base for both variants

Acceptance Criteria

  • SPSC variant exists with no mutex usage
  • Concurrent SPSC benchmark shows improvement over mutex version
  • MPMC variant (circular_buffer<T>) remains unchanged
  • Unit tests cover concurrent single-producer single-consumer scenarios
  • Documentation explains when to use each variant

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions