编译器重新排序与内存重新排序
compiler reordering vs memory reordering
在gcc下,有以下说明可用于设置内存屏障。它们都提供不同的"保护">
asm volatile("" ::: "memory"); // compiler reorder
asm volatile("mfence" ::: "memory"); // memory reordering
C++原子提供简而言之:
- acquire/release semantics
- Sequentially-consistent ordering
我想知道 gcc 原语和C++原子语义之间是否存在直接映射?(例如(那一定是错误的,这只是为了解释目的(,获取/释放语义是为了防止编译器重新排序,顺序一致性排序是为了防止内存重新排序(
或者也许C++不做这种区别? 该语言仅提供适用于同时重新排序的语义?
第一个障碍仅在编译期间适用。编译器完成后,它没有任何影响,因为不会向代码中添加任何内容。这对于避免一些内存排序问题可能很有用(编译器不知道其他线程如何操作这些内存位置,尽管几乎没有任何具有正常设置的编译器敢于对可能出现这种情况的变量进行重新排序(。
然而,这远远不够,因为在现代无序 CPU 上,硬件本身可能会在后台重新排序操作。为了避免这种情况,你有办法告诉硬件要注意,给定你想要达到的确切限制级别和形式(顺序一致性是最严格和"安全"的排序模型,但通常也是最昂贵的性能(。
若要实现这些限制,可以尝试手动维护 ISA 提供的屏障和类似构造(通过内部函数、内联程序集、序列化操作或任何其他技巧(。即使您知道自己在做什么,这通常也很复杂,甚至可能是特定于微体系结构的(某些 CPU 可能会"免费"授予一些限制,使显式屏蔽无用(,因此 c++11 添加了原子语义以使此任务更容易,现在编译器会根据您想要的指定排序模型为您添加必要的代码。
在您的示例中,mfence
是手动执行操作的示例,但您还需要知道在哪里应用它。如果使用得当,mfence 可以足够字符串以提供 seq 一致性,但也非常昂贵,因为它包含一个存储围栏 ( mfence
= sfence
+ lfence
(,这需要从内部缓冲区中排出所有挂起的存储,这是一个缓慢的操作,因为缓冲是为了允许它们延迟提交。另一方面,如果你想要获取/发布语义,你可以选择在正确的位置使用适当的部分围栏来实现它们,或者让编译器为你做到这一点。例如,如果选择后者并在 x86 计算机上运行,您会发现大多数情况下不需要添加任何内容,因为存储具有隐式发布语义,并且加载具有获取语义,但这可能不适用于其他体系结构。
以下是每个体系结构的各种排序语义实现的一个很好的摘要 -http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
- 合并排序不排序自创建数组类 c++
- 使用 Key 对 C++ 中的哈希映射进行排序. 无法排序
- std::排序为排序自定义对象时出现的向量引发错误
- 队列快速排序不排序和打印随机字符串[C ]
- 插入排序中途排序
- C 排序无法排序一组字符串
- C 选择排序不排序
- 气泡排序不排序
- C++:使用 LSD 基数排序字符串排序崩溃
- C 样式的字符串排序与排序和 qsort
- C++ 快速排序不排序
- 如何对包含 pair<int,int> 元素的向量进行排序?排序是根据比较功能完成的
- Introsort(快速排序+堆排序)实现和复杂性
- 用于排序/操作/排序的最佳替代算法
- 没有严格弱排序的排序集
- STL:指针关联排序容器:排序谓词模板
- 排序和排序有什么区别?
- 寻找c++快速排序/插入排序组合中的错误
- 创建没有重复项的新排序向量
- 冒泡排序不排序最后一个数字与此算法