有很多与内存障碍相关的信息。大多数信息指的是多核或多处理器架构。 Stackoverflow上的某处也指出单核处理器不需要内存屏障。
到目前为止,我找不到任何明确的解释,为什么不应该在单核CPU上使用它。假设在线程A中重新排序了加载和存储,并且在两个指令之间发生了上下文切换。在这种情况下,线程B可能没有按预期做出反应。与不同内核上的2个线程相比,为什么单个内核上的上下文切换行为会有所不同? (除了任何缓存一致性问题)
例如来自ARM网站的一些信息:
"从架构上讲,软件必须执行数据内存屏障(DMB)操作: •获取资源之间,例如,通过锁定互斥锁(MUTual EXclusion)或递减信号量,以及对该资源进行任何访问 •在使资源可用之前,例如,通过解锁互斥锁或增加信号量"
这听起来非常清楚,但是在提供的示例中,它们明确提到了多核配置。
答案 0 :(得分:6)
与不同内核上的2个线程相比,为什么单个内核上的上下文切换行为会有所不同? (除了任何缓存一致性问题)
单独核心上的线程可能同时完全。您仍然在单个核心上遇到问题。
Stackoverflow上的某处也指出单核处理器不需要内存屏障。
此信息可能脱离上下文(或未提供足够的上下文)。
Wikipedia's Memory barrier和Memory ordering页面包含无序执行与编译器重新排序优化和编译时间/运行时排序。 管道中有许多地方,内存的顺序可能很重要。在某些情况下,这可能由编译器,操作系统或我们自己的代码来处理。
编译器内存障碍适用于单个CPU。它们对硬件特别有用,其中写入和读取的顺序和时间很重要。
Linux定义了更多types of memory barriers,
这些地图主要适用于DMB
(DSB
和IMB
更多用于代码修改)。
ARM CPU具有多个加载/存储单元的进步越多。理论上,一些非抢占式线程交换机 Note1 (尤其是别名内存)可能会导致多线程单CPU应用程序出现问题。但是,构建这种情况相当困难。
在大多数情况下,CPU通过调度指令处理良好的内存排序。对于单个CPU而言重要的一个常见情况是系统级程序员改变CP15
寄存器。例如,打开MMU时应发出ISB
。对于某些硬件/设备寄存器也是如此。最后,程序加载器将需要障碍以及缓存操作,即使在单CPU系统上也是如此。
UnixSmurf在内存访问顺序上写了这些博客,
主题很复杂,您必须具体说明您正在讨论的障碍类型。
注1:我说非抢占好像发生了中断,单个CPU可能会确保所有未完成的内存请求都已完成。使用非抢占式开关,您可以执行longjmp
之类的操作来更改线程。从理论上讲,您可以在所有写入完成之前更改上下文。系统只需要DMB
中的yield()
来避免它。
答案 1 :(得分:1)
CPU只重新排序已经“发出”的指令,因此上下文切换不会停止管道中已有的任何指令,它们将继续执行直到完成。
当上下文切换完成时,任何这些指令都不可能完成。上下文切换通常会保存所有寄存器的状态,从而创建依赖于修改寄存器的每条指令,以便首先完成。
然而,即使对于仍然执行经过上下文切换(可能是存储器存储)的重新排序指令的不太可能的情况,CPU确保它向软件提供指令以正确顺序执行的外观。因此,当第二个线程尝试访问共享数据时,CPU将确保在允许相关指令执行之前已完成必要的指令。
多核情况实际上是维护对高速缓存/内存的写入顺序的一种情况,以便其他内核看到更改以正确的顺序发生。只需要一个内存屏障。