omegaelit

Lock-free ring buffers for SDR pipelines

An SDR receiver produces samples at a fixed rate whether you are ready or not. If the consumer thread stalls for a few milliseconds, the DMA engine keeps writing, and you either drop samples or block the producer. Neither is acceptable, so the queue between the two has to be boring and predictable.

For a single producer and a single consumer the classic design is enough: two indices, one written by each side, and acquire/release ordering on the handoff. The interesting parts are elsewhere:

// producer
auto tail = tail_.load(std::memory_order_relaxed);
if (tail - cached_head_ == capacity) {
    cached_head_ = head_.load(std::memory_order_acquire);
    if (tail - cached_head_ == capacity) return false; // full
}
slots_[tail & mask] = block;
tail_.store(tail + 1, std::memory_order_release);

In practice a well-tuned off-the-shelf queue beats a hand-rolled one; the point of writing it once is to understand what the library is doing for you.