好吧,我已经从SO关于x86处理器围栏阅读下列适量(LFENCE,SFENCE和MFENCE):
和:
而且我必须说实话,我还不能确定何时需要围栏.我试图从删除完全锁定并尝试通过栅栏使用更细粒度的锁定的角度来理解,以最小化延迟延迟.
首先,这是我不明白的两个具体问题:
有时在进行存储时,CPU会写入其存储缓冲区而不是L1缓存.但是,我不了解CPU执行此操作的条款?
CPU2可能希望加载已写入CPU1的存储缓冲区的值.据我了解,问题是CPU2无法在CPU1的存储缓冲区中看到新值.为什么MESI协议不能将刷新存储缓冲区作为其协议的一部分?
更一般地,可以请人试图描述的总体方案,并帮助时解释LFENCE/ MFENCE和SFENCE被需要的指令?
NB阅读本主题的一个问题是,当我只对Intel x86-64架构感兴趣时,"通常"为多CPU架构编写的文章数量.
英特尔内存模型保证:
http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/
我已经看到声称由于Intel内存模型,SFENCE在x86-64上是多余的,但从来没有LFENCE.上述内存模型规则是否使指令冗余?
Linux的同步原语(自旋锁,互斥锁,RCU)使用内存屏障指令强制重新排序内存访问指令.这种重新排序可以由CPU本身或编译器完成.
有人可以展示一些GCC生成的代码示例吗?我主要对x86感兴趣.我之所以问这个问题,是为了理解GCC如何决定可以重新排序的指令.不同的x86 mirco架构(例如:沙桥与常春藤桥)使用不同的缓存架构.因此,我想知道GCC如何进行有效的重新排序,无论缓存架构如何,都有助于执行性能.一些示例C代码和重新排序的GCC生成的代码将非常有用.谢谢!
GCC汇编了这个:
#include <atomic>
std::atomic<int> a;
int b(0);
void func()
{
b = 2;
a = 1;
}
Run Code Online (Sandbox Code Playgroud)
对此:
func():
mov DWORD PTR b[rip], 2
mov DWORD PTR a[rip], 1
mfence
ret
Run Code Online (Sandbox Code Playgroud)
所以,为我澄清一些事情:
另外,clang(v3.5.1 -O3)这样做:
mov dword ptr [rip + b], 2
mov eax, 1
xchg dword ptr [rip + a], eax
ret
Run Code Online (Sandbox Code Playgroud)
这似乎对我的小脑子更直接,但为什么不同的方法,每个方法的优势是什么?
正如我们从C11-memory_order所知道的那样:http://en.cppreference.com/w/c/atomic/memory_order
从C++ 11-std :: memory_order开始:http://en.cppreference.com/w/cpp/atomic/memory_order
在强排序系统(x86,SPARC,IBM大型机)上, 发布 - 获取顺序是自动的.没有为此同步模式发出额外的CPU指令,只会影响某些编译器优化(例如,禁止编译器在原子存储释放之前移动非原子存储或在原子载荷获取之前执行非原子加载)
但这对于x86-SSE指令是否正确(除了[NT] - 非时间,我们总是必须使用L/S/MFENCE)?
这里说,"sse指令......不要求向后兼容性,并且内存顺序未定义".据信,当需要时,严格的可订购性与旧版本的处理器x86兼容,但是新的命令,即SSE(除了[NT]) - 被剥夺了自动释放 - 获取订单,是吗?
众所周知,在x86上,操作load()和store()内存屏障memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel不需要处理器指令用于缓存和管道,并且汇编程序的代码总是对应std::memory_order_relaxed,并且这些限制仅对编译器的优化是必需的:http:// www. stdthread.co.uk/forum/index.php?topic=72.0
此代码反汇编代码确认store()(MSVS2012 x86_64):
std::atomic<int> a;
a.store(0, std::memory_order_relaxed);
000000013F931A0D mov dword ptr [a],0
a.store(1, std::memory_order_release);
000000013F931A15 mov dword ptr [a],1
Run Code Online (Sandbox Code Playgroud)
但是这段代码并没有为load()(MSVS2012 x86_64)确认这一点,使用lock cmpxchg:
int val = a.load(std::memory_order_acquire);
000000013F931A1D prefetchw [a]
000000013F931A22 mov eax,dword ptr [a]
000000013F931A26 mov edx,eax
000000013F931A28 lock cmpxchg dword ptr [a],edx
000000013F931A2E jne main+36h (013F931A26h)
std::cout << val << "\n";
Run Code Online (Sandbox Code Playgroud)
正如我们从之前的回答中所知道的,它是否在处理器x86/x86_64中指示LFENCE?我们不能使用SFENCE而不是MFENCE顺序一致性.
这里的答案表明MFENCE= SFENCE+ LFENCE,即LFENCE没有我们不能提供顺序一致性的东西.
LFENCE 无法重新排序:
SFENCE
LFENCE
MOV reg, [addr]
Run Code Online (Sandbox Code Playgroud)
- 到 - >
MOV reg, [addr]
SFENCE
LFENCE
Run Code Online (Sandbox Code Playgroud)
例如重新排序MOV [addr], reg LFENCE- > LFENCE MOV [addr], reg由机制提供- 存储缓冲区,它重新排序存储 - 负载以提高性能,并且因为LFENCE它不会阻止它.并SFENCE 禁用此机制.
什么机制禁用LFENCE无法重新排序(x86没有机制 - Invalidate-Queue)?
并且只是在理论上或者在现实中重新排序SFENCE MOV reg, [addr]- > MOV reg, [addr] SFENCE可能吗?如果可能,实际上,什么机制,它是如何工作的?
x86 ×6
assembly ×4
c++ ×2
c++11 ×2
cpu ×2
atomic ×1
c11 ×1
concurrency ×1
gcc ×1
linux-kernel ×1
memory ×1
optimization ×1
sse ×1
x86-64 ×1