【问题标题】:how is a memory barrier in linux kernel is used如何使用 Linux 内核中的内存屏障
【发布时间】:2013-06-03 17:09:05
【问题描述】:

内核源码Documentation/memory-barriers.txt中有一个图解,像这样:

    CPU 1                   CPU 2
    ======================= =======================
            { B = 7; X = 9; Y = 8; C = &Y }
    STORE A = 1
    STORE B = 2
    <write barrier>
    STORE C = &B            LOAD X
    STORE D = 4             LOAD C (gets &B)
                            LOAD *C (reads B)

如果没有干预,CPU 2 可能会在某些情况下感知 CPU 1 上的事件 尽管 CPU 1 发出了写屏障,但实际上是随机顺序:

    +-------+       :      :                :       :
    |       |       +------+                +-------+  | Sequence of update
    |       |------>| B=2  |-----       --->| Y->8  |  | of perception on
    |       |  :    +------+     \          +-------+  | CPU 2
    | CPU 1 |  :    | A=1  |      \     --->| C->&Y |  V
    |       |       +------+       |        +-------+
    |       |   wwwwwwwwwwwwwwww   |        :       :
    |       |       +------+       |        :       :
    |       |  :    | C=&B |---    |        :       :       +-------+
    |       |  :    +------+   \   |        +-------+       |       |
    |       |------>| D=4  |    ----------->| C->&B |------>|       |
    |       |       +------+       |        +-------+       |       |
    +-------+       :      :       |        :       :       |       |
                                   |        :       :       |       |
                                   |        :       :       | CPU 2 |
                                   |        +-------+       |       |
        Apparently incorrect --->  |        | B->7  |------>|       |
        perception of B (!)        |        +-------+       |       |
                                   |        :       :       |       |
                                   |        +-------+       |       |
        The load of X holds --->    \       | X->9  |------>|       |
        up the maintenance           \      +-------+       |       |
        of coherence of B             ----->| B->2  |       +-------+
                                            +-------+
                                            :       :

我不明白,因为我们有写屏障,所以,任何存储都必须在执行 C = &B 时生效,这意味着 B 将等于 2。对于 CPU 2,B 在它得到时应该是 2 C的值,也就是&B,为什么会认为B是7。我真的很困惑。

【问题讨论】:

    标签: linux memory linux-kernel memory-barriers smp


    【解决方案1】:

    关键缺失点是对序列的错误假设:

    LOAD C (gets &B)
    LOAD *C (reads B)
    

    第一次加载必须在第二次加载之前。弱有序架构可以“好像”发生以下情况:

    LOAD B (reads B)  
    LOAD C (reads &B)
    if( C!=&B ) 
        LOAD *C
    else
        Congratulate self on having already loaded *C
    

    推测性的“加载 B”可能发生,例如,因为 B 与早期感兴趣的其他变量或硬件预取抓取它位于同一缓存行。

    【讨论】:

    • 很少有真正的重新排序依赖负载的机制。硬件(或编译器)需要一些理由才能猜测从&amp;B 加载是一种可能有用的方式来满足地址未知的加载。价值预测是一种方式; DEC Alpha had banked L1d caches that could produce this effect的几个型号。分支预测是另一种方式。所以是的,它可能会发生,但机制比简单的硬件预取要奇怪得多。
    【解决方案2】:

    来自文档中标题为“内存屏障不能假设什么?”的部分:

    不保证任何在之前指定的内存访问 内存屏障将在内存屏障完成后完成 操作说明;可以认为屏障在该 CPU 中画一条线 适当类型的访问可能不会交叉的访问队列。

    无法保证 CPU 会看到正确的效果顺序 来自第二个 CPU 的访问,即使 如果 第二个 CPU 使用内存 屏障,除非第一个 CPU 使用匹配的内存屏障(参见 “SMP 屏障配对”小节)。

    内存屏障的作用(当然是以一种非常简单的方式)是确保编译器和 CPU 内的硬件都不会执行任何巧妙的尝试来重新排序跨屏障的加载(或存储)操作,并且 CPU 可以正确感知系统其他部分对内存所做的更改。当加载(或存储)具有其他含义时,这是必要的,例如在访问我们正在锁定的任何内容之前锁定一个锁。在这种情况下,让编译器/CPU 通过对它们进行重新排序来提高访问效率,这对我们程序的正确运行是有害的。

    阅读本文档时,我们需要牢记两点:

    1. 加载意味着将值从内存(或缓存)传输到 CPU 寄存器。
    2. 除非 CPU 共享缓存(或根本没有缓存),否则它们的缓存系统可能会暂时与我们同步。

    事实 #2 是一个 CPU 感知数据的方式与另一个 CPU 不同的原因之一。虽然缓存系统旨在在一般情况下提供良好的性能和一致性,但在特定情况下可能需要一些帮助,例如文档中说明的情况。

    一般而言,正如文档所建议的那样,涉及多个 CPU 的系统中的障碍应该配对,以强制系统同步两个(或所有参与的)CPU 的感知。想象一下这样一种情况:一个 CPU 完成了加载或存储,主内存已更新,但新数据尚未传输到第二个 CPU 的缓存,导致两个 CPU 之间缺乏一致性。

    我希望这会有所帮助。考虑到这一点,我建议再次阅读 memory-barriers.txt,尤其是标题为“CPU 缓存的影响”的部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-24
      • 2015-04-01
      • 2011-09-27
      • 2014-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多