pub struct LockFreeQueue<T> { /* private fields */ }Expand description
A bounded, genuinely lock-free multi-producer multi-consumer queue.
This is an array-based MPMC queue using per-slot sequence numbers (the Vyukov algorithm). Producers and consumers operate through independent atomic head/tail cursors and never acquire a mutex or spinlock. The sequence-number protocol eliminates the ABA problem without tagged pointers or epoch-based reclamation: slots are reused in place, so no node allocation or deallocation occurs during enqueue/dequeue.
§Capacity
The queue is bounded. LockFreeQueue::new creates a queue with
DEFAULT_QUEUE_CAPACITY slots. LockFreeQueue::with_capacity allows
a custom power-of-two capacity. When the queue is full, enqueue
retries with exponential backoff (preserving the unblocked-sender
contract of the previous API), while try_enqueue returns Err(item)
immediately for callers that prefer explicit backpressure.
§Memory safety
Each slot’s Option<T> is written by the producer (replacing None with
Some(item)) and taken by the consumer (replacing Some(item) with
None). The sequence-number protocol guarantees that only one thread
accesses a slot’s data at a time: the producer writes between sequence == pos and sequence == pos+1, the consumer reads between sequence == pos+1 and sequence == pos+capacity.
Implementations§
Source§impl<T> LockFreeQueue<T>
impl<T> LockFreeQueue<T>
Sourcepub fn with_capacity(capacity: usize) -> Self
pub fn with_capacity(capacity: usize) -> Self
Create a new queue with a custom capacity (must be a power of 2).
§Panics
Panics if capacity is 0 or not a power of 2.
Sourcepub fn try_enqueue(&self, item: T) -> Result<(), T>
pub fn try_enqueue(&self, item: T) -> Result<(), T>
Try to enqueue an item without blocking.
Returns Ok(()) if the item was enqueued, or Err(item) if the
queue is full. This is the lock-free fast path: no spinlock, no
mutex, no retry loop.
Sourcepub fn enqueue(&self, item: T)
pub fn enqueue(&self, item: T)
Enqueue an item, retrying with exponential backoff if the queue is full.
This preserves the unblocked-sender contract of the previous API: the
call always eventually succeeds (assuming consumers make progress).
The backoff path uses core::hint::spin_loop and, on std targets,
std::thread::yield_now after heavy contention, but never acquires a
global lock, so multiple producers can enqueue concurrently.
Sourcepub fn try_dequeue(&self) -> Option<T>
pub fn try_dequeue(&self) -> Option<T>
Try to dequeue an item from the front of the queue.
Returns None if the queue is empty.
This is the lock-free fast path: no spinlock, no mutex.