xml*_*lmx 4 c c++ assembly execution instructions
在Windows下,有三个编译器内部函数来实现内存屏障:
1. _ReadBarrier;
2. _WriteBarrier;
3. _ReadWriteBarrier;
Run Code Online (Sandbox Code Playgroud)
但是,我发现了一个奇怪的问题:_ReadBarrier似乎是一个无效的虚函数!以下是VC++ 2012生成的汇编代码.
我的问题是:如何在汇编指令中实现内存屏障功能?
int main()
{
013EEE10 push ebp
013EEE11 mov ebp,esp
013EEE13 sub esp,0CCh
013EEE19 push ebx
013EEE1A push esi
013EEE1B push edi
013EEE1C lea edi,[ebp-0CCh]
013EEE22 mov ecx,33h
013EEE27 mov eax,0CCCCCCCCh
013EEE2C rep stos dword ptr es:[edi]
int n = 0;
013EEE2E mov dword ptr [n],0
n = n + 1;
013EEE35 mov eax,dword ptr [n]
013EEE38 add eax,1
013EEE3B mov dword ptr [n],eax
_ReadBarrier();
n = n + 1;
013EEE3E mov eax,dword ptr [n]
013EEE41 add eax,1
013EEE44 mov dword ptr [n],eax
}
013EEE56 xor eax,eax
013EEE58 pop edi
013EEE59 pop esi
013EEE5A pop ebx
013EEE5B add esp,0CCh
013EEE61 cmp ebp,esp
013EEE63 call __RTC_CheckEsp (013EC3B0h)
013EEE68 mov esp,ebp
013EEE6A pop ebp
013EEE6B ret
Run Code Online (Sandbox Code Playgroud)
_ReadBarrier,_WriteBarrier和_ReadWriteBarrier是影响编译器如何重新排序代码的内在函数 ; 它们与CPU内存屏障完全无关,仅对特定类型的内存有效(请参阅此处的 "受影响的内存" ).
MemoryBarrier()是用来强制CPU内存屏障的内在函数.但是,Microsoft的建议是继续使用std::atomic<T>VC++.
现代处理器能够在实际“完成”指令之前执行相当长的指令,因此在涉及某些类型的内存操作(严格排序)时,使用内存屏障来防止其运行得太早。必需的 - 对于大多数情况,如果在变量 b 之前写入变量 a,或者在 a 之前写入 b,实际上并不重要。但有时确实如此。
x86 指令集有lfence、sfence和fence,它们分别是“隔离”加载、存储和所有内存操作的指令。关于“栅栏”或“屏障”指令的要点是确保屏障指令之前的所有指令在屏障之后的下一条指令可以继续之前完成其加载、存储或两者。
如果您要实现信号量、互斥体或类似指令,这一点很重要,因为在继续读取其他数据之前,存储表示“我已锁定信号量”的值非常重要。比如说,否则事情可能会出错。
请注意,除非您真的知道您在使用内存屏障做什么,否则最好不要使用它们 - 并依赖解决相同问题的现有代码 -std::atomic是资助此类代码的一个地方。我已经编写了相当多的“棘手”代码,但只有一两次我的代码中需要内存屏障。
有几次,我需要让编译器不传播代码,您可以使用“无操作函数”来做到这一点,显然现在甚至有特殊的内部函数可以做到这一点。