什么是 C++11 原子 API 等同于"__asm__易失性( " " ::: "memory" )"''

What is the C++11 atomic API equivalent to ```__asm__ volatile("" ::: "memory")```

本文关键字:memory asm C++11 原子 API 什么 等同于 易失性      更新时间:2023-10-16

代码库有一个定义为__asm__ volatile("" ::: "memory")COMPILER_BARRIER宏。宏的目的是防止编译器跨屏障重新排序读写操作。请注意,这是一个明确的编译器障碍,不是处理器级内存障碍。

事实上,这是相当可移植的,因为AssemblerTemplate中没有实际的汇编指令,只有volatilememory clobber。因此,只要编译器遵守GCCs Extended Asm语法,它就应该可以正常工作。尽管如此,如果可能的话,我很好奇在C++11原子API中表达这一点的正确方式是什么。

以下似乎是正确的想法:atomic_signal_fence(memory_order_acq_rel);

我的理由是:

  • <atomic> API中,只有atomic_signal_fenceatomic_thread_fence不需要针对其进行操作的内存地址
  • atomic_thread_fence会影响内存排序,这对于编译器来说是不需要的
  • Extended Asm版本中的memory clobber不区分读取和写入,因此我们似乎同时想要获取和发布语义,因此似乎至少需要memory_order_acq_rel
  • memory_order_seq_cst似乎没有必要,因为我们不需要跨线程的总顺序——我们只对当前线程中的指令排序感兴趣

是否可以用C++11原子API完全可移植地表达__asm__ volatile("" ::: "memory")的等价物?如果是,那么atomic_signal_fence是正确的API吗?如果是,那么这里需要什么样的内存顺序参数?

或者,我是不是陷入了困境,有更好的方法来解决这个问题?

__asm__ volatile("" ::: "memory")甚至不是一个完整的编译器障碍;它只强制对asm块可能访问其地址的对象进行加载/存储排序,而asm块不包括编译器可以跟踪其地址不泄漏的局部变量。例如,后面跟有__asm__ volatile("" ::: "memory");memset(password, 0, len);可能无法实际将password[]使用的存储器归零。

这可以通过将这些对象的地址作为输入传递到asm块来弥补,但我看不到atomic_signal_fence有任何完美的等价物。最接近的方法可能是将对象的地址存储到外部链接volatile指针对象中(注意使指针而不是指向类型volatile限定),然后atomic_signal_fence必须假设它可能是从信号处理程序访问的。

区分读和写,这样看起来我们想要获取和发布语义

你似乎把不同的问题搞混了。

获取和释放语义都可以对读取和写入产生约束:

  • 释放非正式地表示在屏障启动之前,先前的内存操作已经完成
  • 非正式地获取意味着在屏障完成之前不会开始以下内存操作

然而,这是一个非常简单的解释C++原子屏障是原子学的屏障。它们与原子物体协同工作。当然,线程屏障调用可以自己生成代码,但可以使用一些非原子操作对代码进行重新排序。