ThreadsafeQueueLib is a high-performance, lightweight header-only C++17 library providing robust thread-safe queues. Designed for flexibility and extreme concurrency, it features specialized wait-free, lock-free, and blocking queues tailored for Single-Producer/Single-Consumer (SPSC), Multi-Producer/Single-Consumer (MPSC), and Multi-Producer/Multi-Consumer (MPMC) paradigms.
Whether you need strict boundary allocations, high-throughput dynamic allocations, or block-based chunking mechanisms, ThreadsafeQueueLib gives you fine-grained control over your thread-synchronization primitives.
All queues are easily accessible by including a single header file:
#include <tsfqueue.hpp>Ideal for data pipelining between two distinct threads without lock contention.
tsfqueue::SPSCBounded<T, N>: A bounded lock-free queue that pre-allocates an array ofNelements. Perfect for embedded systems or high-performance scenarios where dynamic memory allocation is strictly prohibited.tsfqueue::SPSCUnbounded<T>: An unbounded lock-free queue utilizing a node-based linked list. It dynamically allocates memory as needed, preventing the queue from ever blocking a producer.tsfqueue::FastSPSCUnbounded<T>: A highly optimized unbounded queue that allocates items in "chunks" or "blocks" of 1024 elements at a time. This drastically reduces the overhead of dynamic allocation compared to the standard unbounded version while remaining entirely lock-free on the enqueue path.
Designed for many-to-one scenarios, such as multiple worker threads pushing results to a single aggregator or logger thread.
tsfqueue::MPSCUnbounded<T>: An unbounded lock-free linked-list queue. Multiple producers safely synchronize using atomic swaps on the tail, while the single consumer pops from the head seamlessly.
The most versatile queues, suitable for thread pools and complex task distribution.
tsfqueue::MPMCBounded<T, N>: A pure lock-free, wait-free bounded queue. It utilizes a pre-allocated array of "Cells" containing sequence numbers. Multiple producers and consumers usecompare_exchange_weakto safely and quickly claim slots without using mutex locks.Nmust be a power of 2.tsfqueue::BlockingMPMCUnbounded<T>: An unbounded queue utilizing standard C++std::mutexandstd::condition_variable. While not lock-free, it provides an exceptionally stable and reliable fallback when absolute raw latency is less critical than CPU-saving sleep states.
#include "tsfqueue.hpp"
#include <iostream>
#include <thread>
int main() {
// Instantiate a lock-free bounded SPSC queue with capacity 1024
tsfqueue::SPSCBounded<int, 1024> queue;
std::thread producer([&queue]() {
for (int i = 0; i < 100; ++i) {
// Spin-wait until successful
while (!queue.try_push(i)) {
std::this_thread::yield();
}
}
});
std::thread consumer([&queue]() {
for (int i = 0; i < 100; ++i) {
int value;
while (!queue.try_pop(value)) {
std::this_thread::yield();
}
std::cout << "Popped: " << value << "\n";
}
});
producer.join();
consumer.join();
return 0;
}The repository contains an exhaustive test suite utilizing Google Test (GTest). The tests stress-test the concurrent nature of the queues under heavy load to guarantee race-condition-free operation and lock-free integrity.
- CMake (3.14 or higher)
- A C++17 compatible compiler (GCC, Clang, or MSVC)
Clone the repository and run the following commands to configure, build, and execute the test suite alongside Google Benchmarks:
# 1. Generate the build files
mkdir -p build && cd build
cmake ..
# 2. Compile the executables
make -j$(nproc)
# 3. Run all tests via CTest
ctest --output-on-failureIf you wish to test a specific queue configuration, you can execute the compiled test binaries directly:
./test_spsc
./test_mpsc
./test_mpmcThroughput was measured using Google Benchmark compiled in Release mode (-O3), with loops instrumented to prevent compiler elision.
To reproduce these benchmarks locally:
mkdir -p build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
./bench_spsc && ./bench_mpsc && ./bench_mpmcComparison of bounded and unbounded SPSC implementations.
| Implementation | Type | Ops/Sec |
|---|---|---|
rigtorp::SPSCQueue |
Bounded | ~198.7 M |
tsfqueue::SPSCBounded |
Bounded | ~121.3 M |
moodycamel::ReaderWriterQueue |
Unbounded | ~31.6 M |
tsfqueue::FastSPSCUnbounded |
Unbounded (Chunked) | ~11.6 M |
tsfqueue::SPSCUnbounded |
Unbounded (Node) | ~4.7 M |
Throughput measured under varying thread contention (1 to 8 concurrent producers).
| Implementation | Ops/Sec (1 Producer) | Ops/Sec (8 Producers) |
|---|---|---|
tsfqueue::MPSCUnbounded |
3.6 M | 7.5 M |
moodycamel::ConcurrentQueue |
3.4 M | 4.4 M |
Throughput measured under varying thread contention (1v1 up to 8v8 threads).
| Implementation | Ops/Sec (1v1) | Ops/Sec (8v8) |
|---|---|---|
tsfqueue::MPMCBounded |
22.8 M | 3.2 M |
moodycamel::ConcurrentQueue |
7.7 M | 3.4 M |
Check out the examples/ directory for ready-to-run use cases. We have compiled a detailed explanation of each architectural pattern in the examples/examples.md file.
Included examples:
01_spsc_logger.cpp- A high-performance background logging thread usingFastSPSCUnbounded.02_mpmc_threadpool.cpp- A multi-threaded task pool architecture usingMPMCBounded.03_mpsc_event_aggregator.cpp- A lock-free event/metrics collector usingMPSCUnbounded.04_spscb_audio_buffer.cpp- A zero-allocation audio stream pipeline usingSPSCBounded.