记忆围栏如何工作?

我需要了解多核机器中的内存栅栏。 说我有这个代码

核心1

mov [_x], 1; mov r1, [_y] 

核心2

 mov [_y], 1; mov r2, [_x] 

现在没有内存栅栏的意外结果是r1和r2在执行后都可以为0。 在我看来,为了解决这个问题,我们应该在两个代码中都放置内存栅栏,因为仅将它放在一个代码中仍然无法解决问题。 如下……

核心1

 mov [_x], 1; memory_fence; mov r1, [_y] 

核心2

 mov [_y], 1; memory_fence; mov r2, [_x] 

我的理解是正确还是我仍然缺少某些东西? 假设架构是x86。 另外,有人能告诉我如何将内存栅栏放入C ++代码中吗?

Fences序列化它们围栅(加载和存储)的操作,也就是说,在执行栅栏之前不会启动其他操作,但是栅栏将不会执行直到所有前面的操作都完成。 引用intel使其含义更加精确(取自MFENCE指令,第3-628页,第2A卷,英特尔指令参考):

此序列化操作可确保在遵循MFENCE指令的任何加载或存储指令之前,按程序顺序在MFENCE指令之前的每个加载和存储指令都变为全局可见。

  1. 当确定要加载到其目的地寄存器中的值时,加载指令被认为变为全局可见。

在C ++中使用fences是很棘手的(C ++ 11可能在某处有栅栏语义,也许其他人有信息),因为它依赖于平台和编译器。 对于使用MSVC或ICC的x86,您可以使用_mm_lfence_mm_sfence_mm_mfence来加载,存储和加载+存储防护(请注意其中一些是SSE2指令)。

注意:这假设是英特尔的观点,即:使用x86(32或64位)或IA64处理器

C ++ 11( ISO / IEC 14882:2011 )定义了一种multithreading感知内存模型。 虽然我不知道当前实现新内存模型的任何编译器,但Anthony Williams的C ++ Concurrency in Action非常好地记录了它。 您可以查看第5章 – C ++内存模型和primefaces类型操作,其中解释了轻松操作和内存屏障。 此外,他是just :: thread库的作者,在我们有新标准的编译器供应商支持之前可以使用它。 just :: thread是boost :: thread库的基础。