Expand description
A fixed capacity multiple-producer, multiple-consumer (MPMC) lock-free queue.
§Deprecation
If a thread is parked, or pre-empted for a long time by an higher-priority task
during an enqueue or dequeue operation, it is possible that the queue ends-up
in a state were no other task can successfully enqueue or dequeue items from it
until the pre-empted task can finish its operation.
In that case, enqueue and dequeue
will return an error, but will not panic or reach undefined behaviour
This makes mpmc unsuitable for some use cases such as using it as a pool of objects.
§When can this queue be used?
This queue should be used for cross-task communication only when items sent over the queue can be dropped in case of concurrent operations, or when it is possible to retry the dequeue/enqueue operation after other tasks have had the opportunity to make progress.
In that case you can safely ignore the warnings using #[expect(deprecated)]
when new is called
For more information, and possible alternative, please see https://github.com/rust-embedded/heapless/issues/583
Note: This module requires atomic compare-and-swap (CAS) instructions. On
targets where they’re not natively available, they are emulated by the
portable-atomic crate.
§Example
This queue can be constructed in const context. Placing it in a static variable lets all
contexts (interrupts/threads/main) safely enqueue and dequeue items.
use core::sync::atomic::{AtomicU8, Ordering};
use heapless::mpmc::Queue;
static Q: Queue<u8, 2> = Queue::new();
fn main() {
// Configure systick interrupt.
loop {
if let Some(x) = Q.dequeue() {
println!("{}", x);
} else {
// Wait for interrupt.
}
}
}
fn systick() {
static COUNT: AtomicU8 = AtomicU8::new(0);
let count = COUNT.fetch_add(1, Ordering::SeqCst);
Q.enqueue(count);
}§Benchmark
Measured on an ARM Cortex-M3 core running at 8 MHz and with zero flash wait cycles, compiled
with -C opt-level=z:
| Method | Time | N |
|---|---|---|
Queue::<u8, 8>::enqueue() | 34 | 0 |
Queue::<u8, 8>::enqueue() | 52 | 1 |
Queue::<u8, 8>::enqueue() | 69 | 2 |
Queue::<u8, 8>::dequeue() | 35 | 0 |
Queue::<u8, 8>::dequeue() | 53 | 1 |
Queue::<u8, 8>::dequeue() | 71 | 2 |
- N denotes the number of interruptions. On Cortex-M, an interruption consists of an interrupt
handler preempting the would-be atomic section of the
enqueue/dequeueoperation. Note that it does not matter if the higher priority handler uses the queue or not. - All execution times are in clock cycles (1 clock cycle = 125 ns).
- Execution time is dependent on
mem::size_of::<T>(), as both operations includeptr::read::<T>()orptr::write::<T>()in their successful path. - The numbers reported correspond to the successful path, i.e.
dequeuereturningSomeandenqueuereturningOk.
§References
This is an implementation of Dmitry Vyukov’s bounded MPMC queue, minus the cache padding.
Structs§
- Queue
Inner - Base struct for
QueueandQueueView, generic over theStorage.