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
Pusher
and Popper
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, Pusher
and Popper
. As
their names suggest, Pusher
can be used to push things into the queue, and
Popper
can be used to pop things out of it.
The Pusher
and Popper
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 Pusher
and Popper
endpoints borrow the central Queue
, and an async
operation
to push or pop through an endpoint borrows that endpoint in turn. Neither
Pusher
nor Popper
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 Pusher or Popper 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 reference to a free element in a queue, where you can deposit an element without checking or waiting.
- Queue endpoint for popping data. Access to a
Popper
only gives you the right to pop data and enquire about pop-related properties. - Queue endpoint for pushing data. Access to a
Pusher
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.