接收异步RDMA传输的缓冲区应使用哪种C++弱原子类型?
核心问题:弱原子标注的选择
- 守卫计数器直接使用
std::atomic<uint64_t>类型,内存序选择Release-Acquire 模型即可,完全不需要使用开销更高的顺序一致性(std::memory_order_seq_cst):- 可靠RDMA连接本身保证写入接收端内存的顺序和发送端提交作业的顺序一致,只要你在发送端先提交消息缓冲区的RDMA写请求、再提交守卫计数器的RDMA写请求,接收端内存中一定会先完成所有消息字节的写入,再更新守卫计数器的值
- 接收端读取守卫计数器时使用
std::memory_order_acquire,该屏障会保证:所有发生在守卫计数器写入之前的内存操作(即对应消息字节的写入),对当前线程完全可见,不会出现读取到旧缓存行的问题 - 如果接收端逻辑需要修改守卫计数器(例如标记消息已消费),写入时使用
std::memory_order_release即可
- 消息缓冲区不需要和守卫使用相同的原子标注:你通过守卫计数器的Acquire屏障已经保证了缓冲区内容的可见性,只要严格遵循「先读取守卫确认消息就绪,再访问对应缓冲区」的规则,缓冲区直接用普通内存即可,给缓冲区增加原子标注只会引入无意义的性能开销。
- 只要遵守上述规则,你要求的守卫值单调递增、缓冲区不会出现新旧内容混杂的语义完全可以得到保障,额外建议将守卫变量和消息缓冲区分配到不同的缓存行,避免伪共享带来的性能损耗和时序异常。
次要问题:是否需要添加volatile关键字
完全不需要添加volatile。C++标准规定std::atomic的操作本身就会阻止编译器对相关内存操作进行乱序重排、也不会将内存值缓存到寄存器中跳过实际内存读取,已经覆盖了你预期volatile能实现的所有效果。volatile的设计初衷是处理内存映射IO等特殊场景,和多线程/外设写入的内存可见性无关,额外添加只会带来不必要的编译限制,没有任何收益。
内容的提问来源于stack exchange,提问作者Ken Birman
相关产品推荐
相关产品推荐

