什么是与`__ASM__Volatile(&Quot;":&Quot;Memory&Quot;)`等价的C++11原子API

2022-04-18 00:00:00 atomic portability c++ c++11 barrier
代码库具有定义为__asm__ volatile("" ::: "memory")COMPILER_BARRIER宏。宏的目的是防止编译器跨障碍对读写进行重新排序。请注意,这显然是编译器障碍,不是处理器级内存障碍。

实际上,这是相当可移植的,因为在汇编模板中没有实际的汇编指令,只有volatilememory装配器。因此,只要编译器支持GCCS扩展ASM语法,它就应该工作得很好。不过,如果可能的话,我很好奇在C++11原子API中表达这一点的正确方式是什么。

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

我的理由是:

  • <atomic>接口中,只有atomic_signal_fenceatomic_thread_fence不需要操作所针对的内存地址。
  • atomic_thread_fence影响内存排序,这不是编译器障碍所需要的。
  • ASM扩展版本中的memory存取器不区分读取和写入,因此我们似乎同时需要获取和释放语义,因此似乎至少需要memory_order_acq_rel
  • memory_order_seq_cst似乎没有必要,因为我们不需要线程之间的总顺序-我们只对当前线程中的指令顺序感兴趣。
是否有可能用C++11原子API完全可移植地表示__asm__ volatile("" ::: "memory")的等价物?如果是,atomic_signal_fence是正确的API吗?如果是,这里需要/合适的内存顺序参数是什么?

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


解决方案

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

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

相关文章