首页 > 解决方案 > C ++:将哪个弱原子用于接收异步的缓冲区。RDMA 传输?

问题描述

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

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

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

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

标签: c++c++17rdmarelaxed-atomics

解决方案


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

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

您不需要制作缓冲区volatile;一般来说,你不应该依赖volatile原子性


推荐阅读