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.