Multithreading 如果在x86中对非读和非写指令重新排序,这有关系吗?

Multithreading 如果在x86中对非读和非写指令重新排序,这有关系吗?,multithreading,assembly,x86,memory-barriers,Multithreading,Assembly,X86,Memory Barriers,mfence说明如下: 对从内存和内存加载的所有数据执行序列化操作 在MFENCE之前发出的存储到内存指令 指示此序列化操作确保每个加载和 在程序中存储MFENCE指令之前的指令 订单在任何加载或存储指令之前全局可见 遵循MFENCE指令 据我所知,x86中没有栅栏指令可以阻止非读和非写指令的重新排序 现在,如果我的程序只有一个线程,即使指令被重新排序,它仍然看起来好像指令是按顺序执行的 但是,如果我的程序有多个线程,并且其中一个线程中的非读和非写指令被重新排序,那么其他线程会注意到这种重新排序

mfence
说明如下:

对从内存和内存加载的所有数据执行序列化操作 在MFENCE之前发出的存储到内存指令 指示此序列化操作确保每个加载和 在程序中存储MFENCE指令之前的指令 订单在任何加载或存储指令之前全局可见 遵循MFENCE指令

据我所知,x86中没有栅栏指令可以阻止非读和非写指令的重新排序

现在,如果我的程序只有一个线程,即使指令被重新排序,它仍然看起来好像指令是按顺序执行的

但是,如果我的程序有多个线程,并且其中一个线程中的非读和非写指令被重新排序,那么其他线程会注意到这种重新排序吗(我假设答案是,否则会有一个围栏指令来停止非读和非写指令的重新排序,或者可能我遗漏了什么)

其他线程会注意到这种重新排序吗

不,除了性能(使用硬件性能计数器计时或直接测量)或微体系结构侧通道(如与超线程/SMT共享物理内核的逻辑内核的ALU端口压力):一个线程可以对自身计时,以了解另一个硬件线程正在执行的操作

线程观察彼此的唯一“正常”方式是加载其他线程存储的数据

甚至加载顺序也只是间接可见的(通过它对另一个线程决定稍后存储的内容的影响)


据我所知,x86中没有栅栏指令可以阻止非读和非写指令的重新排序

在英特尔CPU(但不是AMD)上,
lfence
做到了这一点。英特尔的手册上说,这不仅仅是一个实现细节。它实际上保证了未来的微体系结构

英特尔:

LFENCE在所有之前的
指令在本地完成之前不会执行,以后的指令在LFENCE完成之前不会开始执行

(本地完成=从无序堆芯中退出,即离开ROB)

lfence
作为实际的负载屏障并不特别有用,因为x86不允许从WB内存(仅从WC)进行弱顺序加载。(甚至
movntdqa
prefetchnta
都不能从正常WB内存创建弱顺序加载。)因此,与
sfence
不同,
lfence
基本上不需要用于内存排序,仅用于其特殊效果,如
lfence
rdtsc
。或者用于频谱缓解,以阻止经过它的推测执行



但是作为一个实现细节,在至少包括Skylake的Intel CPU上,
mfence
是无序执行的障碍。请参阅这一点以及更多相关内容。

另一个线程如何检测非内存操作的重新排序?@RaymondChen:如果其中一条指令是
rdtsc
,那么差异在体系结构上成为寄存器中的一个值。但这是一个非常特殊的情况。有趣的事实:至少在Skylake上,
mfence
实际上确实阻止了所有指令的重新排序,比如
lfence
。不过这是一个实现细节;从纸面上看,它只阻止了内存指令的重新排序。(但这也是Linux内核恢复为
锁或[rsp],0
而不是MFENCE的部分原因)