multithreading - 非读和非写指令在 x86 中重新排序是否重要?
问题描述
该mfence
文档说明了以下内容:
对在 MFENCE 指令之前发出的所有从内存加载和存储到内存指令执行序列化操作。这种序列化操作保证了在程序顺序中位于 MFENCE 指令之前的每个加载和存储指令在 MFENCE 指令之后的任何加载或存储指令之前变得全局可见。
据我所知,x86 中没有栅栏指令可以防止非读和非写指令的重新排序。
现在如果我的程序只有一个线程,即使指令被重新排序,它仍然看起来好像指令是按顺序执行的。
但是如果我的程序有多个线程,并且在其中一个线程中对非读和非写指令进行了重新排序,其他线程是否会注意到这种重新排序(我假设答案是否,否则会有一个围栏指令停止非读和非写指令重新排序,或者我错过了什么)?
解决方案
其他线程会注意到这种重新排序吗
不,除了性能(计时或使用硬件性能计数器直接测量)。或微架构侧通道(例如与超线程/SMT 共享物理内核的逻辑内核的 ALU 端口压力):一个线程可以定时自己了解其他硬件线程正在执行的内容。
线程观察彼此的唯一“正常”方式是加载其他线程存储的数据。
甚至加载顺序也只能间接可见(通过它对其他线程决定稍后存储的内容的影响)。
据我所知,x86 中没有栅栏指令可以防止非读和非写指令的重新排序。
在 Intel CPU(但不是 AMD)上,lfence
这样做. 英特尔的手册是这么说的,这不仅仅是一个实现细节。对于未来的微架构,它实际上是有保证的。
Intel 的LFENCE 指令集参考手册入口:
LFENCE 直到所有先前的指令都在本地完成后才执行,并且在 LFENCE 完成之前没有后面的指令开始执行。
(在本地完成 = 从无序核心退出,即离开 ROB)。
lfence
作为实际的负载屏障并不是特别有用,因为 x86 不允许来自 WB 内存(仅来自 WC)的弱排序负载。(甚至不能movntdqa
或prefetchnta
不能从正常的 WB 内存创建弱排序的负载。)所以不像sfence
,lfence
基本上不需要内存排序,只是因为它的特殊效果,比如 lfence
; rdtsc
. 或者对于 Spectre 缓解措施,阻止经过它的推测执行。
但作为一个实现细节,在至少包括 Skylake 在内的 Intel CPU 上,mfence
是乱序执行的障碍。 请参阅加载和存储是唯一被重新排序的指令吗?为此,还有更多相关的东西。
推荐阅读
- angular - 可观察对象的动态数组与 switchMap 函数串联运行,一旦全部完成,即使有些失败也运行
- linux - 无法使用 bash 文件获取打印输出
- sass - 使用插值连接 SASS 变量名称
- python - sklearn TheilSenRegressor ValueError 在为一维回归量设置 fit_intercept=False 时
- c - VisualStudio Cmake IoT 目标交叉编译.exe 添加到程序名称
- javascript - 在有点复杂的数组中添加 id、content
- python - 创建一个在 Python 中全局使用的类对象
- excel - 在 Excel 中,1 个按钮如何控制 2 个单独的功能,第一次单击隐藏特定列,第二次单击取消隐藏列?
- javascript - javascript nested Json object from flat object
- php - PHP版本更新问题