为什么内存屏障只能阻止每个特定内存地址的指令?

时间:2015-09-19 00:28:08

标签: c++ multithreading assembly concurrency atomic

据我所知,无论与“fenced”指令相关的内存地址如何,内存屏障都会“分离”加载/存储(取决于使用的屏障类型)。因此,如果我们有一个原子增量,被装载和存储包围:

LOAD A
STORE B
LOAD C
LOCK ADD D    ; Assume full fence here
LOAD E
STORE F

在A,B和C上操作的指令必须在D之前完成;在D之后,E和F可能无法启动。

但是,由于LOCK仅适用于地址D,为什么要限制其他指令?在电路中实现是否太复杂?或者还有其他原因吗?

1 个答案:

答案 0 :(得分:5)

基本原因是因为围栏的基本意图是强制执行排序,因此如果围栏仅影响对其应用的特定项目的读/写,则它将无法完成其工作。

例如,您经常使用以下模式:

prepare some data
signal that the data is ready

consume some data
signal that the memory used for the data is now free

在这种情况下,用作“信号”的内存位置是您可能要用围栏保护的内容 - 但它不是唯一真正需要保护的内容。

在第一种情况下,我必须确保所有写入数据的代码都被执行,并且只有在完成所有代码之后,才会设置信号。

然后另一个线程可以看到信号已设置。基于此,它知道它可以读取与信号相关的所有数据,而不仅仅是信号本身。如果围栏仅影响信号本身,则意味着写入数据的其他代码可能仍然在信号之后执行 - 然后我们会在写入数据的代码与其他代码尝试之间发生冲突阅读数据。

理论上,我们可以通过围绕每个单独的数据块使用围栏来解决这个问题。实际上,我们几乎肯定希望避免这种情况 - 围栏相当昂贵,因此我们通常更喜欢编写大量数据,然后使用单个围栏来指示内存的整个“块”已准备就绪。