为什么内核文档中需要完全读取内存屏障
Documentation/memory-barriers.txt:709
:
q = READ_ONCE(a);
if (q) {
<read barrier> // why?
p = READ_ONCE(b);
}
解释说 “CPU 可能会通过尝试提前预测结果而短路,以便其他 CPU 认为来自 b 的负载发生在来自 a 的负载之前”
这个解释是否意味着执行此代码片段的 CPU 不会重新排序来自
a
和 b
的读取?
为什么其他 CPU 看到读取的顺序很重要?导致错误的场景示例是什么?
我能看到的唯一问题是 CPU 是否乱序向
a
和 b
发出读取。
内核支持的CPU是否允许进行这种重新排序?
如果是,这条规则在哪里规定? 然后我会看到屏障的必要性,但不是出于解释中所述的原因。
我尝试在 IRC 上询问,但没人知道
投机执行是这里的关键。与存储不同,CPU 可以推测负载,因为它没有任何其他内核可见的可观察到的副作用。
CPU 使用分支预测 + 推测执行来处理控制依赖关系(分支),而不是像数据依赖关系一样。 (数据依赖和控制依赖的区别)。
是的,大多数非 x86 CPU 都会这样做。 (现代 x86 内部进行推测,但如果在架构上允许读取时缓存行不再有效,则需要内存排序机清除。早期加载对于性能来说非常重要,值得推测,特别是因为推测会只要没有其他核心使缓存行无效,例如 true 或 false 共享,则有效。) 相关:
请注意,这些加载是独立的:第二个加载的地址不依赖于第一个加载的结果。如果它们是相关的,则除 DEC Alpha 的某些模型之外的所有体系结构都会在第一个之后执行相关加载,例如 C++memory_order_consume
。 (
CPU 中的相关负载重新排序)。在 Linux 内核内存模型中,您需要smp_read_barrier_depends()
,这是 Linux 仍然支持的 ISA 上的无操作。显然现在在内核中被认为是过时的,隐含在 READ_ONCE
宏中。