跳转至

lock-free ring buffer

是什么 / 解决什么问题

ring buffer 用固定大小数组在生产者和消费者之间传递消息。低延迟系统喜欢它,因为不需要频繁分配内存,数据布局连续,延迟更稳定。

SPSC 模型

单生产者单消费者是最简单也最常用的形式:

producer -> [ ring slots ] -> consumer
             head      tail

生产者只写 head,消费者只写 tail。双方读取对方的 index 来判断满/空。

核心语义

  1. 写数据必须发生在发布 head 之前。
  2. 读数据必须发生在观察到 head 之后。
  3. headtail 应避免 false sharing。
  4. 容量通常取 2 的幂,用 mask 替代取模。

C++ 原子顺序

// producer
buffer[pos] = item;
head.store(next, std::memory_order_release);

// consumer
auto h = head.load(std::memory_order_acquire);
item = buffer[pos];

release/acquire 建立可见性关系:消费者看到新的 head 后,也能看到生产者之前写入的 slot 数据。

背压

队列满时必须有策略:

  • 返回失败,让上游限速
  • 覆盖旧数据,适合某些行情快照场景
  • 自旋等待,适合独占核心
  • 降级丢弃,必须记录指标

面试高频问题

lock-free 是否一定更快

不一定。低竞争下 mutex 可能足够快;复杂 lock-free 结构可能增加 cache miss、ABA 和调试成本。交易系统常用简单、固定模型的 SPSC 队列,而不是追求通用 lock-free 容器。

MPSC/MPMC 为什么更难

多个生产者或消费者会竞争同一个 index,需要 CAS 或分段设计;还要处理发布顺序、空洞、ABA、内存回收等问题。