编程与软件工程snellman.net
这些年我一直把环形缓冲区写错了
I've been writing ring buffers wrong all these years
2016 — 2025,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
作者 Juho Snellman 复盘自己多年写环形缓冲区(ring buffer)的方式,指出一种更简洁的实现:读写索引单调递增、不重置,配合 2 的幂大小和位掩码来取模。文章围绕这一技巧讨论其正确性、历史以及无锁场景下的注意事项。
为什么经久不衰:它把一个常见数据结构的实现细节讲清楚,并引发关于正确性、可读性和实际性能的长期讨论,今天写无锁队列或缓冲区仍会遇到这些问题。
HN 评论精选
环形缓冲区用单调索引和掩码的技巧由来已久;作者强调无锁原子更新等实际难点,并指出 Juho 的关键区别是不重置索引。
这当然不是新发明。我搜索到的最早实例是 2004 年,Andrew Morton 在一次代码审查中随口提到它,似乎早已是成熟技巧;但我看过的大多数实现并没有这么做。我 1992 年就这么做了,所以至少比 2004 年早 12 年,我怀疑更早就有。当时读/写索引由不同处理器更新(甚至端序不同)且无锁,只假设读写指针更新是原子的;搞笑的是有一台硬件并非如此,我在波士顿老 Apollo 工厂用 ICE 和逻辑分析仪花了好几个小时,才搞清某块接在 HP 工作站上的奇怪 EISA 总线扩展卡上到底发生了什么。我不明白为什么非要关注 2^n 大小的缓冲区,就为了能用 & 做掩码。编辑:讨论后我意识到 Juho 的实现和我 1992 年用的不同,因为他从不重置读写索引。
jgrahamc查看英文原文
This is of course not a new invention. The earliest instance I could find with a bit of searching was from 2004, with Andrew Morton mentioning in it a code review so casually that it seems to have been a well established trick. But the vast majority of implementations I looked at do not do this. I was doing this in 1992 so it's at least 12 years older than the 2004 implementation. I suspect it was being done long before that. Back then the read and write indexes were being updated by separate processors (even more fun, processors with different endianness) with no locking. The only assumption being made was that updates to the read/write pointers were atomic (in this case 'atomic' meant that the two bytes that made up a word, counters were 16 bits, were written in atomically). Comically, on one piece of hardware this was not the case and I spent many hours inside the old Apollo works outside Boston with an ICE and a bunch of logic analyzers figuring out what the hell was happening on some weird EISA bus add on to some HP workstation. It's unclear to me why the focus on a 2^n sized buffer just so you can use & for the mask. Edit: having had this discussion I've realized that Juho's implementation is different from the 1992 implementation I was using because he doesn't ever reset the read/write indexes. Oops.
作者认为“错误”实现简单够用,实际瓶颈通常不是取模而是内存屏障。
我喜欢这场讨论整齐地分成三部分:环形缓冲区的历史;关于鞋带的跑题;以及零散、常被忽视的关于其他一切的回复(我这条肯定也算)。我喜欢这类文章,也很享受这一篇,但上面关于“正确”做法的长篇讨论,某种程度上正好解释了为什么那么多人乐意用“错误”的方式。我多次以“错误”方式实现和使用环形缓冲区(也用模运算符!),这种方法的局限从未成为问题或瓶颈,而它的简单性让它比几乎所有其他数据结构都更容易编写和理解。在大多数实际应用中,真正要担心的是内存屏障。
cannam查看英文原文
I love the way this discussion has divided neatly into thirds: history of ringbuffers; digression on shoelaces; fragmentary, widely ignored, replies about everything else (this one included, I'm sure). I like this kind of article and enjoyed this particular one, but the long discussion above about the "right" way to do it goes some way to justifying why so many people are happy to do it the "wrong" way. I've implemented and used ring buffers the "wrong" way many times (with the modulus operator as well!) and the limitations of this method have never been a problem or bottleneck for me, while its simplicity means that it's easier to write and understand than almost any other data structure. In most practical applications, it's memory barriers that you really have to worry about.
评论者补充了一个用 mmap 实现环形缓冲区的项目。
另一个有趣的环形缓冲区实现,使用 mmap:https://github.com/willemt/cbuffer
planckscnst查看英文原文
This is another interesting ring buffer implementation that uses mmap. https://github.com/willemt/cbuffer
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选