什么是C ++ 11原子API,等效于``__asm__ volatile(“ :::“内存”)```

问题描述 投票:8回答:2

代码库的COMPILER_BARRIER宏定义为__asm__ volatile("" ::: "memory")。宏的目的是防止编译器重新排序跨障碍的读取和写入。请注意,这显然是编译器屏障,而not是处理器级内存屏障。

原样,这是相当可移植的,因为在AssemblerTemplate中没有实际的组装指令,只有volatilememory遮盖符。因此,只要编译器采用GCC的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不区分读写,因此看来我们既要获取语义又要释放语义,因此似乎至少需要memory_order_acq_rel
  • memory_order_seq_cst似乎是不必要的,因为我们不需要跨线程的总顺序-我们只对当前线程内的指令排序感兴趣。

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

或者,我是不是在这里杂草丛生,有更好的方法来解决这个问题?

c++ c++11 portability atomicity barrier
2个回答
3
投票

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

这可以通过将这些对象的地址作为输入传递到asm块来解决,但是我看不到atomic_signal_fence有任何完美的等效项。您可能要做的最接近的操作是将对象的地址存储到外部链接volatile指针对象中(请小心使指针(而不是指向类型的指针,必须为volatile限定),然后是atomic_signal_fence必须假设它可以从信号处理程序访问。


0
投票

区分读写,所以看起来我们想要获取和释放语义

您似乎正在混淆不同的问题。

获取和释放语义都可以在读写上创建约束:

  • 非正式发布意味着在启动屏障之前,先前的内存操作已完成
  • 非正式获取意味着后续的内存操作不会在完成屏障之前开始

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

© www.soinside.com 2019 - 2024. All rights reserved.