logoalt Hacker News

Optimizing a lock-free ring buffer

73 pointsby dalvrosalast Tuesday at 12:52 PM65 commentsview on HN

Comments

nitwit005today at 7:18 PM

It would be nice to have an example use case where the technique would show a benefit.

It seems relatively rare to have a single producer and consumer thread, and be worth polling a ring buffer.

dalvrosayesterday at 6:44 PM

From 12M ops/s to 305 M ops/s on a lock-free ring buffer.

In this post, I walk you step by step through implementing a single-producer single-consumer queue from scratch.

This pattern is widely used to share data between threads in the lowest-latency environments.

show 1 reply
ramon156today at 3:03 PM

Something to add to this; if you're focussing on these low-level optimizations, make sure the device this code runs on is actually tuned.

A lot of people focus on the code and then assume the device in question is only there to run it. There's so much you can tweak. I don't always measure it, but last time I saw at least a 20% improvement in Network throughput just by tweaking a few things on the machine.

show 1 reply
jeffbeetoday at 7:18 PM

It's lock-free because it uses ordered loads and stores, which is also how you implement locks. I find the semantic distinction unconvincing. The post is really about how slow the default STL mutex implementation is.

kevincoxtoday at 2:46 PM

Random idea: If you have a known sentinel value for empty could you avoid the reader needing to read the writer's index? Just try to read, if it is empty the queue is empty, otherwise take the item and put an empty value there. Similarly for writing you can check the value, if it isn't empty the queue is full.

It seems that in this case as you get contention the faster end will slow down (as it is consuming what the other end just read) and this will naturally create a small buffer and run at good speeds.

The hard part is probably that sentinel and ensuring that it can be set/cleared atomically. On Rust you can do `Option<T>` to get a sentinel for any type (and it very often doesn't take any space) but I don't think there is an API to atomically set/clear that flag. (Technically I think this is always possible because the sentinel that Option picks will always be small even if the T is very large, but I don't think there is an API for this.)

show 1 reply
pixelpoettoday at 2:56 PM

Great article, thanks for sharing. And such a lovely website too :)

show 1 reply
erickpintortoday at 2:54 PM

Great post!

Would you mind expanding on the correctness guarantees enforced by the atomic semantics used? Are they ensuring two threads can't push to the same slot nor pop the same value from the ring? These type of atomic coordination usually comes from CAS or atomic increment calls, which I'm not seeing, thus I'm interested in hearing your take on it.

show 3 replies
brcmthrowawaytoday at 7:04 PM

Is there a C library that I can get these data structures for free?

brcmthrowawaytoday at 7:01 PM

Random q: What was the first cpu to support atomic instructions?

show 1 reply
Blackthorntoday at 2:43 PM

I had what I thought was a pretty good implementation, but I wasn't aware of the cache line bouncing. Looks like I've got some updates to make.

show 1 reply
sanufartoday at 1:50 PM

Super fun, def gonna try this on my own time later

show 1 reply
devnotes77today at 2:44 PM

[dead]

lukesergeilast Tuesday at 1:09 PM

[flagged]

show 1 reply
hedallast Tuesday at 2:33 PM

[flagged]

show 1 reply
kristianpyesterday at 7:05 PM

This is in C++, other languages have different atomic primitives.

show 5 replies
JonChesterfieldtoday at 2:18 PM

It's obviously, trivially broken. Stores the index before storing the value, so the other thread reads nonsense whenever the race goes against it.

Also doesn't have fences on the store, has extra branches that shouldn't be there, and is written in really stylistically weird c++.

Maybe an llm that likes a different language more, copying a broken implementation off github? Mostly commenting because the initial replies are "best" and "lol", though I sympathise with one of those.

show 2 replies