Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
linux内核中的内存屏障是如何使用的_Linux_Memory_Linux Kernel_Memory Barriers_Smp - Fatal编程技术网

linux内核中的内存屏障是如何使用的

linux内核中的内存屏障是如何使用的,linux,memory,linux-kernel,memory-barriers,smp,Linux,Memory,Linux Kernel,Memory Barriers,Smp,内核源代码文档/memory-barriers.txt中有一个示例,如下所示: 我不明白,因为我们有写屏障,所以任何存储都必须在执行C=&B时生效,这意味着B将等于2。对于CPU 2,当它得到C的值时,B应该是2,也就是&B,为什么它认为B是7。我真的很困惑。从文件中题为“关于记忆障碍,什么是不可假设的?” 不能保证在 记忆屏障将通过完成记忆屏障来完成 指示屏障可以被认为是在该CPU的 适当类型的访问不能交叉的访问队列 及 无法保证CPU将看到正确的效果顺序 来自第二个CPU的访问,即使第二个C

内核源代码文档/memory-barriers.txt中有一个示例,如下所示:


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

从文件中题为“关于记忆障碍,什么是不可假设的?”

不能保证在 记忆屏障将通过完成记忆屏障来完成 指示屏障可以被认为是在该CPU的 适当类型的访问不能交叉的访问队列

无法保证CPU将看到正确的效果顺序 来自第二个CPU的访问,即使第二个CPU使用内存 屏障,除非第一个CPU也使用匹配的内存屏障(请参阅 关于“SMP势垒配对”的小节)

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

阅读本文件时,我们需要记住两件事:

  • 负载意味着将值从内存(或缓存)传输到CPU寄存器
  • 除非CPU共享缓存(或者根本没有缓存),否则它们的缓存系统可能会暂时同步
  • 事实#2是一个CPU可以感知不同于另一个CPU的数据的原因之一。虽然缓存系统的设计目的是在一般情况下提供良好的性能和一致性,但在文档中说明的特定情况下可能需要一些帮助

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


    我希望这有帮助。我建议再次阅读memory-barriers.txt,特别是标题为“CPU缓存的影响”的部分。关键的缺失点是错误的假设,即对于序列:

    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与先前感兴趣的其他变量或硬件预取捕获它时位于同一缓存线上。

    很少有真正的机制用于重新排序依赖的加载。硬件(或编译器)需要一些理由才能猜测从
    &B
    加载可能是满足地址未知的加载的有用方法。价值预测是一种方法;一些模型。分支预测是另一种方法。是的,这是可能发生的,但其机制比简单的硬件预取要奇怪得多。
    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