Assembly 在x86/x86_64处理器上使用LFENCE指令有意义吗?
在互联网上,我经常发现,Assembly 在x86/x86_64处理器上使用LFENCE指令有意义吗?,assembly,x86,x86-64,atomic,memory-barriers,Assembly,X86,X86 64,Atomic,Memory Barriers,在互联网上,我经常发现,LFENCE在x86处理器上毫无意义,也就是说它什么都不做,所以我们可以毫无痛苦地使用SFENCE,因为MFENCE=SFENCE+LFENCE=SFENCENOP=SFENCE 但是如果LFENCE没有意义,那么为什么我们有四种方法来实现x86/x86\u 64中的顺序一致性: 加载(无围栏)和存储+MFENCE 加载(无围栏)和锁定XCHG MFENCE+加载和存储(无围栏) 锁XADD(0)和存储(无围栏) 摘自这里: 以及Herb Sutter在第34页底部的表演
LFENCE
在x86处理器上毫无意义,也就是说它什么都不做,所以我们可以毫无痛苦地使用SFENCE
,因为MFENCE
=SFENCE
+LFENCE
=SFENCE
NOP=SFENCE
但是如果LFENCE
没有意义,那么为什么我们有四种方法来实现x86/x86\u 64中的顺序一致性:
加载
(无围栏)和存储
+MFENCE
加载
(无围栏)和锁定XCHG
MFENCE
+加载
和存储
(无围栏)锁XADD
(0)和存储
(无围栏)LFENCE
没有做任何事情,那么方法(3)将具有以下含义:SFENCE+加载和存储(无围栏)
,但是在加载之前执行SFENCE
没有意义。即如果LFENCE
什么都不做,那么方法(3)就没有意义
在处理器x86/x86\u 64中,它对指令LFENCE
有意义吗
回答:
1.LFENCE
在以下公认答案中所述的情况下是必需的
2.进近(3)不应单独查看,而应与前面的命令结合使用。例如,方法(3):
我们可以将方法代码(3)改写如下:
SFENCE
MOV reg, [addr1] // LOAD-1
MOV [addr2], reg //STORE-1
SFENCE
MOV reg, [addr1] // LOAD-2
MOV [addr2], reg //STORE-2
在这里,SFENCE
可以防止对STORE-1和LOAD-2进行重新排序。为此,after STORE-1命令SFENCE
刷新存储缓冲区。考虑以下场景-这是推测性负载执行理论上会损害顺序一致性的关键情况
最初[x]=[y]=0
CPU0: CPU1:
store [x]<--1 store [y]<--1
load r1<--[y] load r2<--[x]
CPU0:CPU1:
存储[x]底线(TL;DR):LFENCE
单独对内存排序似乎毫无用处,但它并不能使SFENCE
取代MFENCE
。问题中的“算术”逻辑不适用
以下是第8.2.2节(2014年9月的325384-052US版)的摘录,与我在
- 读取不会与其他读取一起重新排序
- 写入不会与旧的读取一起重新排序
- 对内存的写入不会与其他写入一起重新排序,但以下情况除外:
- 使用CLFLUSH指令执行的写操作李>
- 使用非时态移动指令(MOVTI、MOVTQ、MOVTDQ、MOVTPS和MOVTPD)执行的流式存储(写入);及
- 串操作(见第8.2.4.1节)
- 读操作可以通过较旧的写入操作重新排序到不同的位置,但不能通过较旧的写入操作重新排序到同一位置
- 不能使用I/O指令、锁定指令或序列化指令对读取或写入进行重新排序
- 读取无法传递早期LFENCE和MFENCE指令
- 写入无法传递早期的LFENCE、SFENCE和MFENCE指令
- LFENCE指令无法通过早期读取
- SFENCE指令无法传递早期写入
- MFENCE指令无法通过早期读取或写入
由此可知:
MFENCE
是一个完整的内存围栏,用于所有内存类型上的所有操作,无论是非时态的还是非时态的李>
SFENCE
仅防止写入的重新排序(在其他术语中,这是一个存储障碍),并且仅与非时态存储和列为例外的其他指令一起使用
LFENCE
防止读取和后续读取和写入的重新排序(即,它结合了Load和LoadStore屏障)。然而,前两项说明Load和LoadStore屏障始终存在,没有例外。因此,LFENCE
单独对内存排序是无用的
为了支持上一个说法,我查看了英特尔手册所有3卷中提到的LFENCE
的所有地方,没有发现任何地方会说LFENCE
是内存一致性所必需的。即使是迄今为止唯一的非时态加载指令MOVNTDQA
,也提到了MFENCE
,但没有提到LFENCE
更新:有关下面猜测的正确答案,请参见上的答案
MFENCE
是否等同于其他两个栅栏的“总和”,这是一个棘手的问题。乍一看,在三个围栏指令中,只有MFENCE
提供了存储负载屏障,即防止读取与先前写入的重新排序。然而,正确的答案需要知道的不仅仅是上述规则;也就是说,重要的是,所有的围栏指令都是按照彼此的顺序排列的。这使得SFENCE-LFENCE
序列比单个效果的简单结合更强大:该序列还阻止了StoreLoad重新排序(因为加载无法通过LFENCE
,而后者无法通过SFENCE
,后者无法通过存储),因此构成了一个完整的内存围栏(但也请参见下面的注释(*))。但是请注意,这里的顺序很重要,LFENCE-SFENCE
序列没有相同的协同效应
然而,虽然可以说MFENCE~SFENCE-LFENCE
和LFENCE~NOP
,但这并不意味着MFENCE~SFENCE
。我故意使用等价(~)和不相等(=)来强调算术规则在这里不适用。SFENCE
和LFENCE
的相互作用产生了差异;即使负载之间没有重新排序,CPU0: CPU1:
store [x]<--1 store [y]<--1
load r1<--[y] load r2<--[x]