_mm_mfence() 函数做什么

问题描述 投票:0回答:1

查看Intel Intrinsics文档,_mm_mfence

概要如下

对在此指令之前发出的所有从内存加载和存储到内存的指令执行序列化操作。确保按程序顺序在内存栅栏指令之前的每个内存访问在按程序顺序跟随栅栏的任何内存指令之前都是全局可见的。

相应 mfence

 指令的 asm 手册类似。


似乎有很多我无法理解的行话,有人可以澄清一下

_mm_mfence
实际上是做什么的吗

我尝试用谷歌搜索这个问题,但他们没有像样的文档或提出其他问题。

c++ x86 intel intrinsics memory-barriers
1个回答
0
投票

本质上是对编译时和运行时重新排序的完全障碍,包括阻塞 StoreLoad 重新排序,这是 x86 在运行时允许的唯一类型 - https://preshing.com/20120515/memory-reordering-caught-实际情况/。 (x86 的 asm 内存模型是程序顺序加上带有存储转发的存储缓冲区。)

它就像

atomic_thread_fence(seq_cst)
的较慢版本,但也可以处理来自 WC 内存的弱有序 NT 加载,而
lock
指令可能无法做到这一点。 (lock xchg 与 mfence 具有相同的行为吗?)。如果您使用 NT 商店,通常只需要
_mm_sfence()
之后即可与
std::atomic
std::mutex
获取/释放订购保证

进行互操作

(此外,在纸面上不能保证

atomic_thread_fence
可以在北领地商店使用,但实际上
atomic_thread_fence(seq_cst)
可以,尽管
release
不能。)

另请参阅:


在纸面上,

std::atomic_thread_fence(seq_cst)
不一定能阻止一侧的非原子变量与另一侧的非原子变量重新排序,除非还有其他线程可能同步的
std::atomic
加载/存储/RMW -和。例如我认为,在纸面上,
foo=1 ; thread_fence(sc); foo = 2;  atomic_var.store(3, relaxed);
允许消除死店,并且只在屏障之前执行
foo=2
,从而删除
foo=1
分配。 AFAIK,真正的编译器不会这样做。但是对于
_mm_mfence()
,我认为它们不会被允许,因为内在函数对于编译器来说是一个完整的内存屏障,因此所有全局可访问的内存都必须同步并假设被更改。就像 GNU C
asm("mfence" ::: "memory")
。即,与编译器没有定义的函数的非内联函数调用一样强。 (为什么`asm volatile("" ::: "memory")`可以作为编译器屏障?)

内在函数指南只是根据 x86 asm 描述了 asm 指令的行为,而不是它的内在函数还需要阻止编译时重新排序才能在 C++ 中有用。 https://preshing.com/20120625/memory-ordering-at-compile-time/

它确实会发出一条

mfence
指令,该指令等待 存储缓冲区耗尽,然后才能进行后续加载。(或存储,但 x86 上无论如何都不允许 StoreStore 重新排序。)

至少在 Skylake 上,在微代码更新后,

mfence
速度特别慢,以包含类似
lfence
的行为,即不让后续的 ALU 指令执行,直到等待存储缓冲区耗尽为止。有关示例,请参阅 加载和存储是唯一重新排序的指令吗?。这是编译器停止使用
mfence
的原因之一,即使是像
atomic_thread_fence(seq_cst)
这样的东西,而是使用
lock add byte [rsp], 0
或类似的东西。而且在此之前 AMD 上的速度就慢了。

© www.soinside.com 2019 - 2024. All rights reserved.