为什么加载-加载控制依赖需要完整的读内存屏障

问题描述 投票:0回答:1

为什么内核文档中需要完全读取内存屏障

Documentation/memory-barriers.txt:709

q = READ_ONCE(a);
if (q) {
    <read barrier> // why?
    p = READ_ONCE(b);
}

解释说 “CPU 可能会通过尝试提前预测结果而短路,以便其他 CPU 认为来自 b 的负载发生在来自 a 的负载之前”

  1. 这个解释是否意味着执行此代码片段的 CPU 不会重新排序来自

    a
    b
    的读取?

  2. 为什么其他 CPU 看到读取的顺序很重要?导致错误的场景示例是什么?

我能看到的唯一问题是 CPU 是否乱序向

a
b
发出读取。

  1. 内核支持的CPU是否允许进行这种重新排序?

  2. 如果是,这条规则在哪里规定? 然后我会看到屏障的必要性,但不是出于解释中所述的原因。

我尝试在 IRC 上询问,但没人知道

c linux-kernel memory-barriers memory-model
1个回答
0
投票

投机执行是这里的关键。与存储不同,CPU 可以推测负载,因为它没有任何其他内核可见的可观察到的副作用。

CPU 使用分支预测 + 推测执行来处理控制依赖关系(分支),而不是像数据依赖关系一样。 (数据依赖和控制依赖的区别)。

是的,大多数非 x86 CPU 都会这样做。 (现代 x86 内部进行推测,但如果在架构上允许读取时缓存行不再有效,则需要内存排序机清除。早期加载对于性能来说非常重要,值得推测,特别是因为推测会只要没有其他核心使缓存行无效,例如 true 或 false 共享,则有效。) 相关:

为什么存在弱内存模型以及它们的指令顺序是如何选择的?

请注意,这些加载是独立的:第二个加载的地址不依赖于第一个加载的结果。如果它们是相关的,则除 DEC Alpha 的某些模型之外的所有体系结构都会在第一个之后执行相关加载,例如 C++
memory_order_consume

。 (

CPU 中的相关负载重新排序)。在 Linux 内核内存模型中,您需要 smp_read_barrier_depends(),这是 Linux 仍然支持的 ISA 上的无操作。显然现在在内核中被认为是过时的,隐含在 
READ_ONCE
宏中。
    

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