ObzLib concurrency
obz::blocking_queue
A thread-safe queue for producer-consumer work with graceful shutdown.
A Queue Workers Can Sleep On
Imagine a kitchen order rail. Orders arrive from the front of house and workers take the next order when one exists. If there are no orders, the workers do not keep checking the rail over and over. They wait until something arrives.
A game can use the same shape for background asset jobs. The main thread queues requests, and worker threads sleep until there is work to do.
struct load_texture {
std::string path;
};
obz::blocking_queue<load_texture> load_jobs;
load_jobs.push(load_texture{"forest.png"});
load_jobs.push(load_texture{"laser.png"});
Clean Shutdown
Shutdown is where producer-consumer code often becomes awkward. Here, wait_and_pop
returns false when the queue has been closed and no work remains, so worker loops can
exit naturally.
load_texture job;
while (load_jobs.wait_and_pop(job)) {
load_asset(job);
}
Closing the queue wakes waiting workers, but it does not throw away jobs that were already queued. The rail is closed, not emptied.
The Small Synchronisation Rule
The predicate form of wait is the important detail in the implementation. It says exactly
when a worker should wake: when the queue is closed, or when there is at least one value available.
condition_.wait(lock, [this] {
return closed_ || !queue_.empty();
});
That keeps the rule inside the queue instead of spreading condition-variable bookkeeping through the calling code.