Multithreading 何时需要x86 LFENCE、SFENCE和MFENCE指令?
好的,我已经从SO处阅读了关于x86 CPU围栏的以下Qs(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的存储缓冲区中看到新
LFENCE
、SFENCE
和MFENCE
):
LFENCE
/MFENCE
和SFENCE
说明
注意:围绕本主题阅读的一个问题是,当我只对英特尔x86-64体系结构感兴趣时,为多CPU体系结构“一般”撰写的文章数量太多。最简单的答案是:您必须使用三种防护措施之一(
LFENCE
,SFENCE
,MFENCE
)要提供6种数据一致性之一,请执行以下操作:
- 放松的
- 消耗
- 获得
- 释放
- 获得释放
- 连续的
最初,你应该从内存访问的顺序考虑这个问题,这在C++ 11中是很好的文档化和标准化的。你应该先读:
x86/x86\u 64: 1。获取发布一致性:然后,重要的是要理解在x86中访问常规RAM(默认标记为WB-回写,与WT(直写)或UC(不可缓存)的效果相同)通过使用asmMOV
而无需任何其他命令,自动提供获取释放一致性的内存顺序-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)和存储
(无围栏)MOV
访问默认标记为WB-写回的常规RAM。内存在中标记,在每个PTE(页表Enrty)中标记每个页(4 KB连续内存)
但也有一些例外:
ioremap_wc()
,在POSIX中),那么automaticaly只提供获取一致性,我们必须按照下面的段落中的操作- 对内存的写入不会与其他写入一起重新排序,以下例外情况除外:
- 使用CLFLUSH指令执行的写操作李>
- 使用非时态移动指令(MOVTI、MOVTQ、MOVTDQ、MOVTPS和MOVTPD)执行的流式存储(写入);及
- 串操作(见第8.2.4.1节)
SFENCE
,即使您希望获得发布一致性,因为这里自动提供的只是获得一致性,您必须自己进行发布(SFENCE
)
回答您的两个问题:
有时,当执行存储时,CPU将写入其存储缓冲区
而不是一级缓存。不过,我不明白有关的条款
哪个CPU将执行此操作
从用户的角度来看,缓存L1和存储缓冲区的作用不同。L1快,但存储缓冲区快
- Store Buffer(存储缓冲区)-是一个简单的队列,其中只存储写操作,不能重新排序-它用于提高性能并隐藏访问缓存的延迟(L1-1ns、L2-3ns、L3-10ns)(CPU核心认为写操作已存储到缓存并执行下一个命令,但同时写操作仅保存到存储缓冲区,并将保存到缓存