Multithreading 何时需要x86 LFENCE、SFENCE和MFENCE指令?

Multithreading 何时需要x86 LFENCE、SFENCE和MFENCE指令?,multithreading,assembly,x86,cpu,memory-fences,Multithreading,Assembly,X86,Cpu,Memory Fences,好的,我已经从SO处阅读了关于x86 CPU围栏的以下Qs(LFENCE、SFENCE和MFENCE): 以及: 老实说,我还不能完全确定什么时候需要围栏。我试图从移除完全打开的锁和尝试通过围栏使用更细粒度的锁的角度来理解,以最小化延迟 首先,这里有两个我不明白的具体问题: 有时,当执行存储时,CPU将写入其存储缓冲区,而不是一级缓存。然而,我不明白CPU将如何做这件事 CPU2可能希望加载已写入CPU1存储缓冲区的值。据我所知,问题是CPU2无法在CPU1的存储缓冲区中看到新

好的,我已经从SO处阅读了关于x86 CPU围栏的以下Qs(
LFENCE
SFENCE
MFENCE
):

以及:

老实说,我还不能完全确定什么时候需要围栏。我试图从移除完全打开的锁和尝试通过围栏使用更细粒度的锁的角度来理解,以最小化延迟

首先,这里有两个我不明白的具体问题:

有时,当执行存储时,CPU将写入其存储缓冲区,而不是一级缓存。然而,我不明白CPU将如何做这件事

CPU2可能希望加载已写入CPU1存储缓冲区的值。据我所知,问题是CPU2无法在CPU1的存储缓冲区中看到新值。为什么MESI协议不能将刷新存储缓冲区作为其协议的一部分

更一般地说,是否有人可以尝试描述总体情况,并帮助解释何时需要
LFENCE
/
MFENCE
SFENCE
说明


注意:围绕本主题阅读的一个问题是,当我只对英特尔x86-64体系结构感兴趣时,为多CPU体系结构“一般”撰写的文章数量太多。

最简单的答案是:您必须使用三种防护措施之一(
LFENCE
SFENCE
MFENCE
)要提供6种数据一致性之一,请执行以下操作:

  • 放松的
  • 消耗
  • 获得
  • 释放
  • 获得释放
  • 连续的
C++11:

最初,你应该从内存访问的顺序考虑这个问题,这在C++ 11中是很好的文档化和标准化的。你应该先读:

x86/x86\u 64:

1。获取发布一致性:然后,重要的是要理解在x86中访问常规RAM(默认标记为WB-回写,与WT(直写)或UC(不可缓存)的效果相同)通过使用asm
MOV
而无需任何其他命令,自动提供获取释放一致性的内存顺序-
std::memory\u order\u acq\u rel
。 也就是说,对于该内存,仅使用
std::memory\u order\u seq\u cst
来提供顺序一致性是有意义的。当您使用:
std::memory\u order\u released
std::memory\u order\u acq\u rel
时,
std::atomic::store()
(或
std::atomic::load()
)的编译汇编程序代码将是相同的-只有
MOV
没有任何
L/S/MFENCE

注意:但您必须知道,不仅CPU而且C++编译器都可以使用内存对操作进行重新排序,而且所有6个内存屏障都会影响C++编译器,无论CPU体系结构如何

那么,你必须知道,它是如何从C++到ASM(原生机器代码)编译的,或者你怎么能在汇编程序上编写它呢?要提供任何一致性,您可以简单地编写

MOV
,例如
MOV-reg[addr]
MOV[addr],reg

2。顺序一致性:但要提供顺序一致性,必须使用隐式(
LOCK
)或显式围栏(L/S/
MFENCE
),如下所述:

  • 加载
    (无围栏)和
    存储
    +
    MFENCE
  • 加载
    (无围栏)和
    锁定XCHG
  • MFENCE
    +
    加载
    存储
    (无围栏)
  • 锁XADD
    (0)和
    存储
    (无围栏)
  • 例如,GCC使用1,而MSVC使用2。(但您必须知道,MSVS2012有一个bug:)

    然后,您可以阅读Herb Sutter,您的链接:

    规则的例外情况:

    此规则适用于使用
    MOV
    访问默认标记为WB-写回的常规RAM。内存在中标记,在每个PTE(页表Enrty)中标记每个页(4 KB连续内存)

    但也有一些例外:

  • 如果我们将页表中的内存标记为写组合(
    ioremap_wc()
    ,在POSIX中),那么automaticaly只提供获取一致性,我们必须按照下面的段落中的操作

  • 见对我问题的答复:

    • 对内存的写入不会与其他写入一起重新排序,以下例外情况除外:
      • 使用CLFLUSH指令执行的写操作
      • 使用非时态移动指令(MOVTI、MOVTQ、MOVTDQ、MOVTPS和MOVTPD)执行的流式存储(写入);及
      • 串操作(见第8.2.4.1节)
    在第1和第2种情况下,您必须在对同一地址的两次写入之间使用额外的
    SFENCE
    ,即使您希望获得发布一致性,因为这里自动提供的只是获得一致性,您必须自己进行发布(
    SFENCE

    回答您的两个问题:

    有时,当执行存储时,CPU将写入其存储缓冲区 而不是一级缓存。不过,我不明白有关的条款 哪个CPU将执行此操作

    从用户的角度来看,缓存L1和存储缓冲区的作用不同。L1快,但存储缓冲区快

    • Store Buffer(存储缓冲区)-是一个简单的队列,其中只存储写操作,不能重新排序-它用于提高性能并隐藏访问缓存的延迟(L1-1ns、L2-3ns、L3-10ns)(CPU核心认为写操作已存储到缓存并执行下一个命令,但同时写操作仅保存到存储缓冲区,并将保存到缓存