heapless

Module spsc

source
Expand description

Fixed capacity Single Producer Single Consumer (SPSC) queue

Implementation based on https://www.codeproject.com/Articles/43510/Lock-Free-Single-Producer-Single-Consumer-Circular

NOTE: This module is not available on targets that do not support atomic loads and are not supported by atomic_polyfill. (e.g., MSP430).

§Examples

  • Queue can be used as a plain queue
use heapless::spsc::Queue;

let mut rb: Queue<u8, 4> = Queue::new();

assert!(rb.enqueue(0).is_ok());
assert!(rb.enqueue(1).is_ok());
assert!(rb.enqueue(2).is_ok());
assert!(rb.enqueue(3).is_err()); // full

assert_eq!(rb.dequeue(), Some(0));
  • Queue can be split and then be used in Single Producer Single Consumer mode
use heapless::spsc::Queue;

// Notice, type signature needs to be explicit for now.
// (min_const_eval, does not allow for default type assignments)
static mut Q: Queue<Event, 4> = Queue::new();

enum Event { A, B }

fn main() {
    // NOTE(unsafe) beware of aliasing the `consumer` end point
    let mut consumer = unsafe { Q.split().1 };

    loop {
        // `dequeue` is a lockless operation
        match consumer.dequeue() {
            Some(Event::A) => { /* .. */ },
            Some(Event::B) => { /* .. */ },
            None => { /* sleep */ },
        }
    }
}

// this is a different execution context that can preempt `main`
fn interrupt_handler() {
    // NOTE(unsafe) beware of aliasing the `producer` end point
    let mut producer = unsafe { Q.split().0 };

    // ..

    if condition {
        producer.enqueue(Event::A).ok().unwrap();
    } else {
        producer.enqueue(Event::B).ok().unwrap();
    }

    // ..
}

§Benchmarks

Measured on a ARM Cortex-M3 core running at 8 MHz and with zero Flash wait cycles

-C opt-level3
Consumer<u8>::dequeue15
Queue<u8>::dequeue12
Producer<u8>::enqueue16
Queue<u8>::enqueue14
  • All execution times are in clock cycles. 1 clock cycle = 125 ns.
  • Execution time is dependent of mem::size_of::<T>(). Both operations include one memcpy(T) in their successful path.
  • The optimization level is indicated in the first row.
  • The numbers reported correspond to the successful path (i.e. Some is returned by dequeue and Ok is returned by enqueue).

Structs§

  • A queue “consumer”; it can dequeue items from the queue NOTE the consumer semantically owns the head pointer of the queue
  • An iterator over the items of a queue
  • A mutable iterator over the items of a queue
  • A queue “producer”; it can enqueue items into the queue NOTE the producer semantically owns the tail pointer of the queue
  • A statically allocated single producer single consumer queue with a capacity of N - 1 elements