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

use*_*112 1 c++ concurrency assembly multithreading atomic

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

LOAD A
STORE B
LOAD C
LOCK ADD D    ; Assume full fence here
LOAD E
STORE F
Run Code Online (Sandbox Code Playgroud)

在A,B和C上操作的指令必须在D之前完成; 并且E和F可能直到D之后才开始.

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

Jer*_*fin 5

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

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

prepare some data
signal that the data is ready
Run Code Online (Sandbox Code Playgroud)

和:

consume some data
signal that the memory used for the data is now free
Run Code Online (Sandbox Code Playgroud)

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

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

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

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