← 首页 / 单步看一次无锁写入 待审核
FastQueue::write()

单步看一次无锁写入

counter 是绝对偏移(一直累加的 uint64_t),取 % CAP 才映射到 buffer 物理槽位——因此天然区分「空 / 满」,且写满后自然环绕覆盖最旧数据。下方绿色 = 可读区、斜纹 = 正在写入区(此刻对 readers 不可见)。单步跟一次写入,看两个 counter 如何把 buffer 切成两段。

设计出处:CppCon 演讲 When Nanoseconds Matter: Ultrafast Trading Systems in C++(David Gross, Optiver)。本页是对其中 FastQueue 那页设计的可视化复现。

为什么写入要分三步、且顺序固定? 写之前先推进 mWriteCounter,等于先把 [r, r+n) 这段「从可读区里摘出来」标记为写入中——哪怕 consumer 此刻正巧读到这一段,也会看到它属于写入区而跳过,不会读到写了一半的脏数据。数据 memcpy 完,再推进 mReadCounter 把这段合回可读区「发布」。两个 store 都用 release 序,保证 memcpy 的写入对随后看到新 counter 的 consumer 可见。

1 · alignas 的灵魂:消除 false sharing

CPU 缓存以 cache line(通常 64 字节)为单位。若两个 counter 落在同一条 cache line,producer 改 mWriteCounter 会让整条 line 失效——即便 consumer 只想读 mReadCounter,也被迫从内存 / 远核重新加载。这就是 false sharing(伪共享)。alignas(64) 让每个 counter 独占一条 line,写一个不再殃及另一个。点下面按钮模拟 producer 反复写 mWriteCounter:

代价与取舍。 alignas 用「空间」换「时间」:每个 counter 多占大半条 cache line 的 padding,但换来读写互不打扰的稳定低延迟。同理 mBuffer 也对齐——它和 counter 分处不同 cache line,数据拷贝不会反过来作废 counter。在纳秒级尾延迟里,省下的这一次次跨核 cache line 颠簸,正是「nanoseconds matter」。

相关链接

  • When Nanoseconds Matter: Ultrafast Trading Systems in C++ CppCon (David Gross) 本页设计的出处:FastQueue 的 counter / cache-line 布局、以及一整套纳秒级低延迟工程实践。
  • False sharing Wikipedia 伪共享的成因(cache line 粒度 + MESI 一致性协议)与典型的 padding / alignment 缓解手段。
  • std::atomic cppreference 原子操作与 memory_order(本页用到的 release / relaxed)的语义定义。
  • alignas specifier cppreference 对齐说明符的用法;配合 std::hardware_destructive_interference_size 取 cache line 大小。
  • Circular buffer Wikipedia 环形缓冲区基础:用单调 counter + 取模映射物理槽位,区分空 / 满的几种约定。