C++:哪个弱原子用于接收异步的缓冲区。 RDMA 传输?

C++: Which weak atomic to use for buffers that receive async. RDMA transfers?

Derecho system(用于数据复制、分布式协调、Paxos——超快的开源 C++ 库)是围绕异步 RDMA 网络原语构建的。发送方可以不暂停地写入接收方,使用 RDMA 传输到接收方内存。通常这是分两步完成的:我们在一次操作中传输数据字节,然后通过递增计数器或设置标志来通知接收方:“消息 67 现在已经为您准备好了”。很快接收方就会注意到消息 67 已准备就绪,此时它将访问该消息的字节。

预期语义:“看到计数器更新应该意味着接收方的 C++ 代码将看到消息的字节。”在 PL 术语中,我们需要在守卫更新和消息字节之间建立内存栅栏。各个缓存行也必须顺序一致:我的守卫将遍历 67、68 等值,......我不想要任何形式的混搭值或非单调排序,例如 C++ 可能出现的情况读取陈旧的缓存行,或错误地将陈旧的值保存在内存中。消息缓冲区本身也是如此:这些字节可能会覆盖旧字节,我不想看到某种混搭。

这是我问题的症结所在:我需要一个弱原子,它会[准确地]施加所需的屏障,而不会引入不必要的开销。哪个注解合适? “消息”的弱原子注释与计数器(“守卫”)的弱原子注释是否相同?

第二个问题:如果我用适当的弱原子声明我的缓冲区,我是否还需要说它是“易失性”的,或者 C++ 会因为内存被声明为弱原子而实现这一点吗?

原子计数器,无论其类型如何,都不能保证任何不受 CPU 控制的内存。在 RDMA 传输开始之前,您需要确保 RDMA 区域的 CPU 缓存已刷新 无效,然后当然不会读取或写入该区域而 RDMA 传输正在进行中。当 RDMA 设备发出传输完成信号时,您可以更新计数器。

等待计数器递增的线程不应重新排序读取计数器后完成的任何加载或存储,因此正确的内存顺序是 std::memory_order_acquire。所以基本上,你想要Release-Acquire ordering,尽管在更新计数器的线程中没有任何东西可以“释放”。

您不需要制作缓冲区volatile;一般 you should not rely on volatile for atomicity.