All Projects → rigtorp → Spscqueue

rigtorp / Spscqueue

Licence: mit
A bounded single-producer single-consumer wait-free and lock-free queue written in C++11

Programming Languages

cpp
1120 projects
cpp11
221 projects

Projects that are alternatives of or similar to Spscqueue

Concurrencyfreaks
Stars: ✭ 299 (-2.61%)
Mutual labels:  concurrency, lock-free
optimistic lock coupling rs
🍋: A General Lock following paper "Optimistic Lock Coupling: A Scalable and Efficient General-Purpose Synchronization Method"
Stars: ✭ 21 (-93.16%)
Mutual labels:  concurrency, lock-free
linked-blocking-multi-queue
A concurrent collection that extends the existing Java concurrent collection library, offering an optionally-bounded blocking "multi-queue" based on linked nodes.
Stars: ✭ 41 (-86.64%)
Mutual labels:  queue, concurrency
Xenium
A C++ library providing various concurrent data structures and reclamation schemes.
Stars: ✭ 225 (-26.71%)
Mutual labels:  concurrency, lock-free
lfqueue
Minimize lock-free queue ever!
Stars: ✭ 107 (-65.15%)
Mutual labels:  queue, lock-free
Jctools
jctools.github.io/jctools
Stars: ✭ 2,833 (+822.8%)
Mutual labels:  concurrency, lock-free
beems
a bee-queue based minimalist toolkit for building fast, decentralized, scalable and fault tolerant microservices
Stars: ✭ 33 (-89.25%)
Mutual labels:  queue, concurrency
Thmap
Concurrent trie-hash map library
Stars: ✭ 51 (-83.39%)
Mutual labels:  concurrency, lock-free
hatrack
Fast, multi-reader, multi-writer, lockless data structures for parallel programming
Stars: ✭ 55 (-82.08%)
Mutual labels:  queue, lock-free
easy-promise-queue
An easy JavaScript Promise queue which is automatically executed, concurrency controlled and suspendable.
Stars: ✭ 31 (-89.9%)
Mutual labels:  queue, concurrency
Goconcurrentqueue
Go concurrent-safe, goroutine-safe, thread-safe queue
Stars: ✭ 127 (-58.63%)
Mutual labels:  concurrency, queue
psched
Priority-based Task Scheduling for Modern C++
Stars: ✭ 59 (-80.78%)
Mutual labels:  queue, concurrency
Unagi Chan
A haskell library implementing fast and scalable concurrent queues for x86, with a Chan-like API
Stars: ✭ 115 (-62.54%)
Mutual labels:  concurrency, queue
concurrent-ll
concurrent linked list implementation
Stars: ✭ 66 (-78.5%)
Mutual labels:  concurrency, lock-free
Left Right
A lock-free, read-optimized, concurrency primitive.
Stars: ✭ 1,245 (+305.54%)
Mutual labels:  concurrency, lock-free
async
async is a tiny C++ header-only high-performance library for async calls handled by a thread-pool, which is built on top of an unbounded MPMC lock-free queue.
Stars: ✭ 25 (-91.86%)
Mutual labels:  queue, lock-free
Arq
Fast job queuing and RPC in python with asyncio and redis.
Stars: ✭ 695 (+126.38%)
Mutual labels:  concurrency, queue
Awesome Lockfree
A collection of resources on wait-free and lock-free programming
Stars: ✭ 1,046 (+240.72%)
Mutual labels:  concurrency, lock-free
think-async
🌿 Exploring cooperative concurrency primitives in Python
Stars: ✭ 178 (-42.02%)
Mutual labels:  queue, concurrency
queueable
Convert streams to async ⌛ iterables ➰
Stars: ✭ 43 (-85.99%)
Mutual labels:  queue, concurrency

SPSCQueue.h

Build Status C/C++ CI License

A single producer single consumer wait-free and lock-free fixed size queue written in C++11.

Example

SPSCQueue<int> q(1);
auto t = std::thread([&] {
  while (!q.front());
  std::cout << *q.front() << std::endl;
  q.pop();
});
q.push(1);
t.join();

See src/SPSCQueueExample.cpp for the full example.

Usage

  • SPSCQueue<T>(size_t capacity);

    Create a SPSCqueue holding items of type T with capacity capacity. Capacity needs to be at least 1.

  • void emplace(Args &&... args);

    Enqueue an item using inplace construction. Blocks if queue is full.

  • bool try_emplace(Args &&... args);

    Try to enqueue an item using inplace construction. Returns true on success and false if queue is full.

  • void push(const T &v);

    Enqueue an item using copy construction. Blocks if queue is full.

  • template <typename P> void push(P &&v);

    Enqueue an item using move construction. Participates in overload resolution only if std::is_constructible<T, P&&>::value == true. Blocks if queue is full.

  • bool try_push(const T &v);

    Try to enqueue an item using copy construction. Returns true on success and false if queue is full.

  • template <typename P> void try_push(P &&v);

    Try to enqueue an item using move construction. Returns true on success and false if queue is full. Participates in overload resolution only if std::is_constructible<T, P&&>::value == true.

  • T *front();

    Return pointer to front of queue. Returns nullptr if queue is empty.

  • pop();

    Dequeue first elment of queue. Invalid to call if queue is empty. Requires std::is_nothrow_destructible<T>::value == true.

Only a single writer thread can perform enqueue operations and only a single reader thread can perform dequeue operations. Any other usage is invalid.

Huge page support

In addition to supporting custom allocation through the standard custom allocator interface this library also supports standard proposal P0401R3 Providing size feedback in the Allocator interface. This allows convenient use of huge pages without wasting any allocated space. Using size feedback is only supported when C++17 is enabled.

The library currently doesn't include a huge page allocator since the APIs for allocating huge pages are platform dependent and handling of huge page size and NUMA awareness is application specific.

Below is an example huge page allocator for Linux:

#include <sys/mman.h>

template <typename T> struct Allocator {
  using value_type = T;

  struct AllocationResult {
    T *ptr;
    size_t count;
  };

  size_t roundup(size_t n) { return (((n - 1) >> 21) + 1) << 21; }

  AllocationResult allocate_at_least(size_t n) {
    size_t count = roundup(sizeof(T) * n);
    auto p = static_cast<T *>(mmap(nullptr, count, PROT_READ | PROT_WRITE,
                                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
                                   -1, 0));
    if (p == MAP_FAILED) {
      throw std::bad_alloc();
    }
    return {p, count / sizeof(T)};
  }

  void deallocate(T *p, size_t n) { munmap(p, roundup(sizeof(T) * n)); }
};

See src/SPSCQueueExampleHugepages.cpp for the full example on how to use huge pages on Linux.

Implementation

Memory layout

The underlying implementation is a ring buffer.

Care has been taken to make sure to avoid any issues with false sharing. The head and tail pointers are aligned and padded to the false sharing range (cache line size). The slots buffer is padded with the false sharing range at the beginning and end.

This implementation allows for arbitrary non-power of two capacities, instead allocating a extra queue slot to indicate full queue. If you don't want to waste storage for a extra queue slot you should use a different implementation.

References:

Testing

Testing lock-free algorithms is hard. I'm using two approaches to test the implementation:

  • A single threaded test that the functionality works as intended, including that the element constructor and destructor is invoked correctly.
  • A multithreaded fuzz test that all elements are enqueued and dequeued correctly under heavy contention.

Benchmarks

Throughput benchmark measures throughput between 2 threads for a SPSCQueue<int> of size 256.

Latency benchmark measures round trip time between 2 threads communicating using 2 queues of type SPSCQueue<int>.

The following numbers are for a 2 socket machine with 2 x Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz.

NUMA Node / Core / Hyper-Thread Throughput (ops/ms) Latency RTT (ns)
#0,#0,#0 & #0,#0,#1 63942 60
#0,#0,#0 & #0,#1,#0 37739 238
#0,#0,#0 & #1,#0,#0 25744 768

Cited by

SPSCQueue have been cited by the following papers:

  • Peizhao Ou and Brian Demsky. 2018. Towards understanding the costs of avoiding out-of-thin-air results. Proc. ACM Program. Lang. 2, OOPSLA, Article 136 (October 2018), 29 pages. DOI: https://doi.org/10.1145/3276506

About

This project was created by Erik Rigtorp <[email protected]>.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].