Task Queues for C++: From Simple to Complex
A Task Queue is one of the key patterns in multithreaded programming. It allows organizing asynchronous execution of work: one or more producer threads add tasks, while a pool of worker threads processes them. In C++, there are both standard tools and specialized libraries for this purpose.
1. Standard Queue: std::queue with Locks
The simplest option is to use std::queue together with a mutex and a condition variable. This is suitable for small projects where synchronization overhead is not critical.
#include <queue>#include <mutex>#include <condition_variable>
template<typename T>class ThreadSafeQueue { std::queue<T> q_; mutable std::mutex mtx_; std::condition_variable cv_;public: void push(T value) { std::lock_guard<std::mutex> lock(mtx_); q_.push(std::move(value)); cv_.notify_one(); }
T pop() { std::unique_lock<std::mutex> lock(mtx_); cv_.wait(lock, [this]{ return !q_.empty(); }); T val = std::move(q_.front()); q_.pop(); return val; }};Pros: simplicity, built into the standard library.
Cons: locks on every operation, potential contention and priority inversion.
2. boost::lockfree::queue — Lock-Free Queue
The Boost library provides lock-free data structures based on CAS operations. boost::lockfree::queue is a lock-free multithreaded queue using a fixed or dynamic memory pool.
#include <boost/lockfree/queue.hpp>
boost::lockfree::queue<int> queue(128); // fixed size
void producer() { for (int i = 0; i < 1000; ++i) { while (!queue.push(i)) { // if the queue is full, wait or discard } }}
void consumer() { int value; while (queue.pop(value)) { process(value); }}Pros: high performance with small queue sizes, no locks.
Cons: debugging complexity, limited size (for the fixed version), need for memory reclamation.
3. Intel TBB (Threading Building Blocks) — tbb::concurrent_queue
Intel TBB is an industrial-grade library for parallel programming. Its tbb::concurrent_queue (and tbb::concurrent_bounded_queue) are optimized for high load.
#include <tbb/concurrent_queue.h>
tbb::concurrent_bounded_queue<Task> task_queue;task_queue.set_capacity(1024); // limit the size
// Producertask_queue.push(std::move(task));
// ConsumerTask t;if (task_queue.try_pop(t)) { t.execute();}Pros: excellent scalability, support for bounded/unbounded modes, integration with the TBB task scheduler.
Cons: Apache 2.0 license (previously GPL), dependency on the entire TBB library.
4. libdispatch (Grand Central Dispatch) via C++ Binding
GCD is a queue management system from Apple, available on macOS/iOS. There is a dispatch/queue wrapper for C++. On Linux, you can use libdispatch (open source).
#include <dispatch/dispatch.h>
dispatch_queue_t queue = dispatch_queue_create("com.example.myqueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{ // task 1});
dispatch_async(queue, ^{ // task 2});
dispatch_release(queue);Pros: efficient thread management, automatic scaling to the number of cores.
Cons: limited