Search code examples
c++multithreadingproducer-consumerlock-freewait-free

Ring buffer for a wait-free producer and a blocking consumer


I have a producer thread that produces objects at a rate that might (temporarily) be too fast for the consumer thread to consume. Therefore, I'd like a FIFO that buffers the remaining work. Once the FIFO is full, the producer shall simply retire or retry later. Also, I would like to be able to notify the consumer that no more work is to be done (without enqueuing a special object into the FIFO). The producer shall not get slowed down and the consumer shall not waste CPU cycles, so I have the following requirements:

  • Circular ring buffer of fixed size.
  • Producer shall never wait: It needs to be able to enqueue elements as quickly as possible.
  • Consumer shall be able to block: No busy-waiting for a potentially slow producer. A hybrid lock would be nice.

I am envisioning the following C++ class:

template <typename T, std::size_t N>
class spsc_circular_half_blocking {
    std::array<T, N> buffer;
    // bookkeeping, atomics, mutexes etc. go here
public:
    bool try_push(const T&); // returns whether object could be enqueued
    void notify(); // notifies consumer
    bool wait_pop(T&); // returns whether object was dequeued or notification was received
};

Being able to modify the elements in-place would be nice. It may also use dynamic allocation of the buffer (e.g. size is passed to constructor, buffer is a unique_ptr).

Now for my questions. Is this thing even possible (on x86, at least)?

  • If yes, how would it work? I would really like some implementation, preferably but not necessarily C++.
  • If no, why not?

Pointers to related material, even if it does not exactly fulfill my needs, would also be greatly appreciated.


Solution

  • One solution would be to use boost single-producer single-consumer queue with you own signalling and blocking.