UnboundedSipmuc¶
Canonical API Documentation
lockfreequeues is a backwards-compatibility wrapper. UnboundedSipmuc forwards directly to canonical lockfree's unbounded SPMC Queue. For canonical documentation, see lockfree Documentation.
Unbounded single-producer, multiple-consumer (SPMC) queue using linked segments.
Overview¶
UnboundedSipmuc provides an unbounded SPMC queue where a single producer distributes work to multiple consumers. Uses DEBRA / NEBR epoch-based memory reclamation (via canonical lockfree) for safe segment deallocation, and a segment-level tail atomic for safe publication to concurrent consumers.
Note: With a single producer there is no race on the slot itself, so each segment carries one
tail: Atomic[int]rather than a per-slot commit/sequence marker. The producer writes the item then bumpstailwith release ordering; consumers acquire-loadtailand treat any slot below it as fully published. The unbounded MP variants (UnboundedMupsic,UnboundedMupmuc) need a per-slot committed flag because multiple producers race ontailvia CAS to claim a slot before writing, sotailcan advance past not-yet-written slots; the bounded MP variants use a per-slot sequence-counter protocol with generation rollover. See slot-ownership-typestates.md for the full distinction across all four bounded × unbounded × SP × MP combinations.
Performance characteristics:
- Push: Wait-free (bounded steps)
- Pop: Lock-free (CAS coordination between consumers)
Usage¶
import lockfreequeues
# Generic params are [SegmentSize, ItemType, MaxThreads]; auto-create
# overload (no args) heap-allocates a private DebraManager owned by
# the queue. For multi-queue setups sharing a manager, use the
# explicit `(manager, strategy)` overload instead.
var queue = newUnboundedSipmuc[64, int, 4]()
# Producer pushes
queue.push(42)
# Each consumer gets a handle (auto-registers a thread slot in the
# manager). Slots are not released until the manager is destroyed, so
# reuse one handle per long-running consumer thread rather than calling
# `getConsumer()` repeatedly.
var consumer1 = queue.getConsumer()
var consumer2 = queue.getConsumer()
# Consumers compete for items
let item = consumer1.pop() # some(42) - one consumer wins
When to Use¶
Choose UnboundedSipmuc when:
- Single source distributes to multiple workers
- Number of consumers may change at runtime
- Workload is bursty or unpredictable
- Cannot predetermine maximum queue size
Choose bounded Sipmuc instead when:
- Memory must be bounded
- Consumer count is fixed at compile time
- Queue size is predictable