Expand description
A queue for moving data from one future/task into another.
This is a “single-producer, single-consumer” queue that splits into separate
Push
and Pop
endpoints – at any given time, there is at most one of
each alive in your program, ensuring that pushes and pops are not coming
from multiple directions.
You create a queue by calling Queue::new
and passing it a reference to its
backing storage. To actually use the queue, however, you must call
Queue::split
to break it into two endpoints, Push
and Pop
. As their
names suggest, Push
can be used to push things into the queue, and Pop
can be used to pop things out of it.
The Push
and Pop
can then be handed off to separate code paths, so long
as they don’t outlive the Queue
and its storage. (The compiler will ensure
this.)
This queue uses the Rust type system to ensure that only one code path is
attempting to push or pop the queue at any given time, because both Push
and Pop
endpoints borrow the central Queue
, and an async
operation to
push or pop through an endpoint borrows that endpoint in turn. Neither
Push
nor Pop
can be cloned or copied, ensuring the single-producer
single-consumer property.
Implementation
This is implemented as a concurrent lock-free Lamport queue. This has two implications:
- If you can arrange the lifetimes correctly (i.e. make the queue static) it is actually safe to operate either Push or Pop from an ISR.
- It fills up at N-1 elements because one empty slot is used as a sentinel to distinguish full from empty.
The adaptations to modern memory ordering semantics are taken from Nhat Minh Lê et al’s paper “Correct and Efficient Bounded FIFO Queues,” though this implementation does not use all of the optimizations they identified.
Structs
- A “permit” giving its holder the right to push one element into a queue, without waiting.
- Queue endpoint for popping data. Access to a
Pop
only gives you the right to pop data and enquire about pop-related properties. - Queue endpoint for pushing data. Access to a
Push
only gives you the right to push data and enquire about push-related properties. - A single-producer, single-consumer queue. The
Queue
struct contains the controlling information for the queue overall, and borrows the storage.