readerwriterqueue

repository·master·Indexed 26 days ago

https://github.com/cameron314/readerwriterqueue

A high-performance, single-producer, single-consumer (SPSC) lock-free queue implementation for C++11. It provides ReaderWriterQueue for lock-free queuing, BlockingReaderWriterQueue for blocking consumer capabilities, and BlockingReaderWriterCircularBuffer for fixed-capacity blocking queuing without dynamic allocation.

Tokens
1.6K
Snippets
5
Records
6
Agent score
39%

What's inside readerwriterqueue

  1. Install readerwriterqueue into system directories

    master

    You can install the library into your system's include directory using CMake:

    mkdir build
    cd build
    cmake ..
    make install

    After installation, you can include it using the following path:

    #include <readerwriterqueue/readerwriterqueue.h>
  2. Integrate readerwriterqueue into your project

    master

    You can use this library in two ways:

    1. Header-only approach: Drop readerwriterqueue.h (or readerwritercircularbuffer.h) and atomicops.h directly into your source code and include them.
    2. CMake approach: Use FetchContent to pull the repository into your build system.

    Requirements:

    • A C++11 compliant compiler (MSVC 2010+, GCC 4.7+, ICC 13+).
    • Note for GCC users: You must use GCC 4.7 or above. GCC 4.6 has a bug that prevents atomic fence primitives from working correctly.
  3. Configure readerwriterqueue with CMake FetchContent

    master

    To use readerwriterqueue as a target in an existing CMake project, add the following to your CMakeLists.txt:

    include(FetchContent)
    
    FetchContent_Declare(
      readerwriterqueue
      GIT_REPOSITORY    https://github.com/cameron314/readerwriterqueue
      GIT_TAG           master
    )
    
    FetchContent_MakeAvailable(readerwriterqueue)
    
    add_library(my_target main.cpp)
    target_link_libraries(my_target PUBLIC readerwriterqueue)

    Then include the header in your source code:

    #include <readerwriterqueue.h>
  4. Use ReaderWriterQueue for SPSC lock-free queuing

    master

    The ReaderWriterQueue<T> is a single-producer, single-consumer (SPSC) lock-free queue. It is designed for exactly two threads: one producing and one consuming.

    Key Methods:

    • enqueue(T&&): Adds an item. Will allocate memory if the queue is full.
    • try_enqueue(T&&): Adds an item only if there is space. Guaranteed never to allocate memory.
    • try_dequeue(T&): Returns true and populates the variable if an item was removed; returns false if the queue was empty.
    • peek(): Returns a pointer to the front item (consumer only). Returns nullptr if the queue is empty.
    • size_approx(): Returns an approximate size of the queue.
    using namespace moodycamel;
    
    ReaderWriterQueue<int> q(100);       // Reserve space for at least 100 elements up front
    
    q.enqueue(17);                       // Will allocate memory if the queue is full
    bool succeeded = q.try_enqueue(18);  // Will only succeed if the queue has an empty slot (never allocates)
    assert(succeeded);
    
    int number;
    succeeded = q.try_dequeue(number);  // Returns false if the queue was empty
    
    assert(succeeded && number == 17);
    
    // You can also peek at the front item of the queue (consumer only)
    int* front = q.peek();
    assert(*front == 18);
    succeeded = q.try_dequeue(number);
    assert(succeeded && number == 18);
    front = q.peek(); 
    assert(front == nullptr);           // Returns nullptr if the queue was empty
  5. Use BlockingReaderWriterCircularBuffer for fixed-capacity blocking queuing

    master

    The BlockingReaderWriterCircularBuffer<T> is a blocking SPSC queue with a fixed number of slots (no dynamic allocation).

    Key Methods:

    • try_enqueue(T&&): Attempts to enqueue without blocking.
    • wait_enqueue(T&&): Blocks until space is available to enqueue.
    • try_dequeue(T&): Attempts to dequeue without blocking.
    • wait_dequeue(T&): Blocks until an item is available.
    • wait_dequeue_timed(T&, duration): Blocks until an item is available or timeout occurs.
    BlockingReaderWriterCircularBuffer<int> q(1024);  // pass initial capacity
    
    q.try_enqueue(1);
    int number;
    q.try_dequeue(number);
    assert(number == 1);
    
    q.wait_enqueue(123);
    q.wait_dequeue(number);
    assert(number == 123);
    
    q.wait_dequeue_timed(number, std::chrono::milliseconds(10));
  6. Use BlockingReaderWriterQueue for blocking SPSC queuing

    master

    The BlockingReaderWriterQueue<T> provides the same API as ReaderWriterQueue<T> but adds blocking capabilities for the consumer:

    • wait_dequeue(T&): Blocks indefinitely until an item is available.
    • wait_dequeue_timed(T&, duration): Blocks until an item is available or the specified timeout is reached.

    Warning: wait_dequeue will block indefinitely if the queue is empty. Destroying the queue while a thread is waiting on it results in undefined behavior. Ensure the queue has a static lifetime or another thread will eventually produce an element.

    BlockingReaderWriterQueue<int> q;
    
    std::thread reader([&]() {
        int item;
        for (int i = 0; i != 100; ++i) {
            // Fully-blocking:
            q.wait_dequeue(item);
        }
    });
    
    std::thread writer([&]() {
        for (int i = 0; i != 100; ++i) {
            q.enqueue(i);
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    });
    
    writer.join();
    reader.join();
    
    assert(q.size_approx() == 0);