ObzLib lock-free queue

obz::mpsc_ring_queue

A fixed-capacity queue where multiple producers publish to one consumer.

Many Loading Bays, One Dispatch Desk

The SPSC queue is a private conveyor belt between two rooms. The MPSC queue keeps the same one-way idea, but now several workers can place work onto the belt while one thread drains it.

A game might use this when several worker threads finish jobs that need to be applied on the main thread: pathfinding results, visibility checks, generated chunks, or background asset work.

struct completed_job {
    entity_id entity;
    job_result result;
};

obz::mpsc_ring_queue<completed_job, 1024> completed_jobs;

Claiming A Slot Before Publishing

The extra complexity is that producers can arrive at the same time. Each producer needs to claim a slot without stepping on another producer, then publish the value when construction is complete.

const auto sequence = current->sequence.load(std::memory_order_acquire);
const auto diff = static_cast<std::ptrdiff_t>(sequence) -
                  static_cast<std::ptrdiff_t>(write);

if (diff == 0) {
    if (write_index_.value.compare_exchange_weak(write,
                                                 write + 1,
                                                 std::memory_order_relaxed,
                                                 std::memory_order_relaxed)) {
        break;
    }
} else if (diff < 0) {
    return false; // full
}

The per-cell sequence number is the small piece of bookkeeping that lets producers reserve space and lets the single consumer tell the difference between a claimed slot and a published value.

The Type Requirement Matters

The nothrow requirements are not decorative. A producer claims its FIFO position before constructing the object, so throwing after the claim would leave a hole that could block the single consumer.

static_assert(std::is_nothrow_constructible_v<T, Args...>,
              "mpsc_ring_queue::try_emplace requires nothrow construction");

That is the library teaching point: in concurrent code, type requirements can protect the data structure's progress guarantees.

More Libraries