ringbuf
Lock-free SPSC FIFO ring buffer with direct access to inner data.
Features
- Lock-free operations - they succeed or fail immediately without blocking or waiting.
- Arbitrary item type (not only
Copy). - Items can be inserted and removed one by one or many at once.
- Thread-safe direct access to the internal ring buffer memory.
ReadandWriteimplementation.- Overwriting insertion support.
- Different types of buffers and underlying storages.
- Can be used without
stdand even withoutalloc(using only statically-allocated memory). - Async and blocking versions (see this section).
- Can optionally use the
portable-atomiccrate to allow usage on smaller systems without CAS operations.
Usage
At first you need to create the ring buffer itself. HeapRb is recommended but you may choose another one.
After the ring buffer is created it may be splitted into pair of Producer and Consumer.
Producer is used to insert items to the ring buffer, consumer - to remove items from it.
Capacity must be in 1..=usize::MAX / 2, including for zero-sized items.
Constructors panic if the capacity is zero or exceeds this limit.
Types
There are several types of ring buffers provided:
LocalRb. Only for single-threaded use.SharedRb. Can be shared between threads. Its frequently used instances:HeapRb. Contents are stored in dynamic memory. Recommended for use in most cases.StaticRb. Contents can be stored in statically-allocated memory.
You may also provide your own generic parameters.
Performance
SharedRb needs to synchronize CPU cache between CPU cores. This synchronization has some overhead.
To avoid multiple unnecessary synchronizations you may use methods that operate many items at once(push_slice/push_iter, pop_slice, etc.).
Caching endpoints also avoid repeatedly fetching the opposite endpoint's index when progress is possible.
All completed operations publish their index updates immediately, including each step of pop_iter.
skip and clear take constant time for items without destructors, such as u8.
Items that need destruction are dropped individually, with each slot kept occupied until its destructor finishes.
For single-threaded usage LocalRb is recommended because it is slightly faster than SharedRb due to absence of CPU cache synchronization.
Migrating from deferred publication
Deferred publication in frozen endpoints and PopIter could lead to double drops if they were forgotten with core::mem::forget.
Publication no longer depends on running their destructors.
Frozen, FrozenProd, FrozenCons, and freeze() are deprecated compatibility APIs. Their removal is reserved for a future breaking release.
Existing calls remain available, but code relying on delayed visibility or rollback must be updated:
- Use
CachingProdandCachingConsdirectly and remove calls tofreeze,commit,fetch, andsync. Operations publish their changes immediately and fetch the opposite endpoint's progress as needed. FrozenProd::discardis now a no-op. Stage items outside the ring buffer if they may need to be discarded, and insert them only when ready to publish.PopIterreleases each slot as soon as it yields the item. Itscommitmethod is deprecated and does nothing. It still yields only the items present when it was created. Usepop_sliceto batch removals.
Examples
Simple
use ;
let rb = new;
let = rb.split;
prod.try_push.unwrap;
prod.try_push.unwrap;
assert_eq!;
assert_eq!;
prod.try_push.unwrap;
assert_eq!;
assert_eq!;
assert_eq!;
No heap
use ;
const RB_SIZE: usize = 1;
let mut rb = default;
let = rb.split_ref;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
Overwrite
Ring buffer can be used in overwriting mode when insertion overwrites the oldest element if the buffer is full.
use ;
let mut rb = new;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
Note that push_overwrite requires exclusive access to the ring buffer
so to perform it concurrently you need to guard the ring buffer with mutex or some other lock.
Derived crates
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.