3 unstable releases
0.2.0 | Jun 3, 2024 |
---|---|
0.1.1 | May 30, 2024 |
0.1.0 | May 30, 2024 |
#380 in Concurrency
Used in 2 crates
26KB
186 lines
Direct Ring Buffer
This crate provides a high-performance, lock-free ring buffer for single-producer,
single-consumer scenarios. The main components of this crate are the Producer
and
Consumer
structures, which allow for efficient elements writing and reading,
respectively.
Overview
A ring buffer is a fixed-size buffer that works as a circular queue. This implementation
uses a lock-free approach, making it suitable for real-time applications where minimal
latency is crucial. The buffer supports generic types with the Copy
trait. The Copy
trait is mainly used to prevent the use of types implementing Drop
, as the buffer is
allocated uninitialized.
Features
- Single-Producer, Single-Consumer: Designed for scenarios with a single writer and a single reader.
- Lock-Free: Utilizes atomic operations for synchronization, avoiding the need for mutexes or other locking mechanisms.
- Slice-Based I/O: Supports reading and writing multiple elements at a time using slices, enhancing performance for bulk operations.
- Closure-Based Access: Provides direct access to the buffer through closures, allowing for flexible and efficient elements processing.
- Single Element Read/Write: Supports not only bulk operations but also single element read and write operations.
Example
use direct_ring_buffer::{create_ring_buffer, Producer, Consumer};
let (mut producer, mut consumer) = create_ring_buffer::<u8>(5);
// Writing data to the buffer
producer.write_slices(|data, _offset| {
data[..3].copy_from_slice(&[1, 2, 3]);
3
}, None);
assert!(producer.write_element(4));
assert!(producer.write_element(5));
assert_eq!(producer.available(), 0);
// Reading data from the buffer
consumer.read_slices(|data, _offset| {
assert_eq!(data, &[1, 2, 3, 4, 5]);
4
}, None);
assert_eq!(consumer.read_element(), Some(5));
assert_eq!(consumer.read_element(), None);
assert_eq!(consumer.available(), 0);
- Writing Elements (Step 1):
The producer writes the elements [1, 2, 3] into the buffer using
write_slices
. - Writing Elements (Step 2):
Next, the producer writes the element [4] into the buffer using
write_element
. - Writing Elements (Step 3):
Then, the producer writes the element [5] into the buffer using
write_element
, filling the buffer. - Buffer Check: After these write operations, it checks that the buffer is full.
- Reading Elements (Step 1):
The consumer reads the first four elements [1, 2, 3, 4] from the buffer using
read_slices
. - Reading Elements (Step 2):
Then, the consumer reads the remaining element [5] using
read_element
. - Final Buffer Check: Finally, it checks that the buffer is empty.
Safety and Performance
This implementation ensures that elements are accessed safely through unsafe
blocks
with proper checks. The use of atomic operations ensures minimal overhead for
synchronization, making it suitable for high-performance applications.
Optimized for Bulk Operations
Designed to handle multiple elements at once, reducing overhead for batch processing. Single-element operations may incur significant overhead.
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.