Linux 内核使用lock; addl $0,0(%%esp)
作为写屏障,而 RE2 库使用xchgl (%0),%0
作为写屏障。有什么区别,哪个更好?
x86 也需要读屏障指令吗? RE2 将其读屏障函数定义为 x86 上的无操作,而 Linux 将其定义为lfence
或无操作取决于 SSE2 是否可用。什么时候lfence
必需的?
引用 IA32 手册(第 3A 卷,第 8.2 章:内存排序):
在定义为可回写缓存的内存区域的单处理器系统中,内存排序模型遵循以下原则 [..]
- 读取不会与其他读取重新排序
- 写入不会与较旧的读取重新排序
- Writes to memory are not reordered with other writes, with the exception of
- 写入执行与
CLFLUSH
操作说明
- 使用非临时移动指令执行流式存储(写入)([此处的指令列表])
- 字符串操作(参见第 8.2.4.1 节)
- 读取可以与对不同位置的较旧写入进行重新排序,但不能与对同一位置的较旧写入进行重新排序。
- 读取或写入无法使用 I/O 指令、锁定指令或序列化指令重新排序
- 读取无法通过
LFENCE
and MFENCE
指示
- 写入无法通过
SFENCE
and MFENCE
指示
注意:上面的“在单处理器系统中”有点误导。相同的规则分别适用于每个(逻辑)处理器;然后,手册继续描述多个处理器之间的附加排序规则。与这个问题有关的唯一一点是
简而言之,只要您写入回写内存(只要您不是驱动程序或图形程序员,您就会看到所有内存),大多数 x86 指令几乎顺序一致 - 唯一的重新排序x86 CPU 可以执行重新排序稍后(独立)读取以在写入之前执行。关于写屏障的主要问题是它们有一个lock
前缀(隐式或显式),它禁止所有重新排序并确保多处理器系统中的所有处理器以相同的顺序看到操作。
此外,在回写存储器中,读取永远不会重新排序,因此不需要读取屏障。最新的 x86 处理器对于流存储和写组合内存(通常用于映射图形内存)具有较弱的内存一致性模型。这就是各种fence
指令开始发挥作用;它们对于任何其他内存类型都不是必需的,但 Linux 内核中的某些驱动程序确实处理写组合内存,因此它们只是以这种方式定义其读屏障。每个存储器类型的订购模型列表位于第 11.3.1 卷第 11.3.1 节中。 IA-32 手册的 3A。简短版本:直写式、回写式和写保护式允许推测性读取(遵循上面详述的规则),不可缓存和强不可缓存内存具有强大的排序保证(没有处理器重新排序,读/写立即执行,用于 MMIO )和写入组合内存的排序较弱(即需要栅栏的宽松排序规则)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)