Home

Awesome

Lock-free ring buffer

Build Status

Lock-free multi-producer single-consumer (MPSC) ring buffer which supports contiguous range operations and which can be conveniently used for message passing. The implementation is written in C11 and distributed under the 2-clause BSD license.

API

Notes

The consumer will return a contiguous block of ranges produced i.e. the ringbuf_consume call will not return partial ranges. If you think of produced range as a message, then consumer will return a block of messages, always ending at the message boundary. Such behaviour allows us to use this ring buffer implementation as a message queue.

The implementation was extensively tested on a 24-core x86 machine, see the stress test for the details on the technique. It also provides an example how the mechanism can be used for message passing.

Caveats

This ring buffer implementation always provides a contiguous range of space for the producer. It is achieved by an early wrap-around if the requested range cannot fit in the end. The implication of this is that the ringbuf_acquire call may fail if the requested range is greater than half of the buffer size. Hence, it may be necessary to ensure that the ring buffer size is at least twice as large as the maximum production unit size.

It should also be noted that one of the trade-offs of such design is that the consumer currently performs an O(n) scan on the list of producers.

Example

Producers:

if ((w = ringbuf_register(r, worker_id)) == NULL)
	err(EXIT_FAILURE, "ringbuf_register")

...

if ((off = ringbuf_acquire(r, w, len)) != -1) {
	memcpy(&buf[off], payload, len);
	ringbuf_produce(r, tls);
}

Consumer:

if ((len = ringbuf_consume(r, &off)) != 0) {
	process(&buf[off], len);
	ringbuf_release(r, len);
}