单核 ARM 上的内存屏障

Memory barrier on single core ARM

有很多与内存屏障相关的信息。大多数信息指的是多核或多处理器架构。 Whosebug 上的某个地方也指出单核处理器不需要内存屏障。

到目前为止,我找不到任何明确的解释为什么单核 CPU 不需要它。假设在线程 A 中对加载和存储进行了重新排序,并且两个指令之间发生了上下文切换。在这种情况下,线程 B 可能不会按预期做出反应。与不同内核上的 2 个线程相比,为什么单个内核上的上下文切换表现不同? (任何缓存一致性问题除外)

例如来自 ARM 网站的一些信息:

“从架构上定义,软件必须执行数据内存屏障 (DMB) 操作: •在获取资源(例如,通过锁定互斥量(互斥)或递减信号量)和对该资源进行任何访问之间 •在使资源可用之前,例如,通过解锁互斥量或递增信号量

这听起来很清楚,但是在提供的示例中,它们明确指的是多核配置。

Why would a context switch on a single core behave differently compared to 2 threads on different cores ? (except any cache coherency issues)

不同内核上的线程可能完全同时运行。你在单核上仍然有问题。

Somewhere here on Whosebug is also stated that memory barriers are not required on single core processors.

此信息可能被断章取义(或没有提供足够的上下文)。


Wikipedia's Memory barrier and Memory ordering 页包含 乱序执行与编译器重新排序优化 编译 time/Run 时间[=71= 】 订购。在 管道 中有很多地方内存的顺序可能很重要。在某些情况下,这可能由编译器、OS 或我们自己的代码处理。

编译器内存障碍 适用于单个 CPU。它们对于写入和读取的顺序和时间很重要的硬件特别有用。

Linux 定义更多 types of memory barriers,

  1. Write/Store.
  2. 数据依赖。
  3. Read/Load.
  4. 一般内存障碍。

主要是这些映射很好地映射到 DMBDSBIMB 更多用于代码修改)。

越先进的 ARM CPU 有多个 load/store 单元。理论上,某些非抢占式线程开关 Note1(尤其是别名内存)可能会导致 多线程 单个 CPU 应用程序。但是,构建这种情况相当困难。

在大多数情况下,良好的内存排序由 CPU 通过调度指令处理。与单个 CPU 相关的常见情况是系统级程序员更改 CP15 寄存器。例如,打开 MMU 时应发出 ISB。对于某些 hardware/device 寄存器可能也是如此。最后,程序加载器将需要屏障和缓存操作,即使在单个 CPU 系统上也是如此。

UnixSmurf 内存访问排序

上写了这些博客

话题很复杂,您必须具体说明所讨论的障碍类型。

注1:我说non preemptive好像是中断发生,单CPU大概能保证所有未完成内存请求完成。使用 非抢占式 开关,您可以执行 longjmp 之类的操作来更改线程。理论上,您可以在所有写入完成之前更改上下文。系统只需要 yield() 中的 DMB 即可避免它。

CPU 仅重新排序已经 "issued" 的指令,因此上下文切换不会停止任何已经在管道中的指令,它们将继续执行直到完成。

不太可能在上下文切换完成时,这些指令中的任何一个都还未完成。上下文切换通常会保存所有寄存器的状态,从而创建对每条修改寄存器的指令的依赖性以先完成。

然而,即使对于重新排序的指令在上下文切换之后仍然执行的不太可能的情况,可能是内存存储,CPU 确保它为软件提供指令以正确的方式执行的外观命令。因此,当第二个线程尝试访问共享数据时,CPU 将确保在允许相关指令执行之前完成必要的指令。

多核情况实际上是维护写入 cache/memory 的顺序的情况,以便其他核心看到更改以正确的顺序发生。为此只需要内存屏障。