13

某处,有一次我读到了记忆栅栏(障碍)。据说内存栅栏会导致多个 CPU 内核之间的缓存同步。

所以我的问题是:

  1. 操作系统(或 CPU 本身)如何知道哪些内核需要同步?

  2. 它是否同步所有 CPU 内核的缓存?

  3. 如果对 (2) 的回答是“是”并且假设同步操作并不便宜,那么使用内存栅栏会减慢我的应用程序未使用的内核吗?例如,如果我有一个单线程应用程序在我的 8 核 CPU 上运行,它会减慢 CPU 的所有其他 7 个内核,因为某些缓存线必须与所有这些内核同步吗?

  4. 上面的问题是完全无知的,围栏的工作方式完全不同吗?

4

3 回答 3

8
  1. 操作系统不需要知道,每个 CPU 核心都按照它的指示去做:每个带有内存栅栏的核心都必须在之前或之后执行某些操作,仅此而已。一个核心不会“与”其他核心同步,它会同步相对于自身的内存访问。
  2. 一个核心中的栅栏并不意味着其他核心与之同步,因此通常您会有两个(或更多)栅栏:一个在写入器中,一个在读取器中。在一个核心上执行的栅栏不需要影响任何其他核心。当然,一般来说不能保证这一点,只是希望理智的架构不会过度序列化多核执行。
于 2014-09-13T11:49:25.383 回答
5

通常,内存栅栏用于对本地操作进行排序。以这个伪汇编代码为例:

load A
load B

许多 CPU 不保证 B 确实在 A 之后加载,B 可能位于由于某些其他内存负载而更早加载到缓存中的缓存行中。如果你引入栅栏,

load A
readFence
load B

您可以保证 B 在 A 之后从内存中加载。如果 B 在缓存中但比 A 旧,它将被重新加载。

商店的情况与此相反。和

store A
store B

一些 CPU 可能会在写入 A 之前决定将 B 写入内存。同样,可能需要在两条指令之间设置一个栅栏来强制执行操作的顺序。是否需要内存栅栏始终取决于架构。


通常,您成对使用内存栅栏:

  • 如果一个线程想要发布一个对象,它首先构造该对象,然后在将指向该对象的指针写入公共已知位置之前执行写栅栏。

  • 想要接收对象的线程从公开的内存位置读取指针,然后执行读取栅栏以确保基于该指针的所有进一步读取实际上给出了发布线程想要的值。

如果缺少任何一个栅栏,读取器可能会在初始化之前读取对象的一个​​或多个数据成员的值。疯狂随之而来。

于 2014-09-13T13:01:15.407 回答
1

如果您说八个内核,并且每个内核都在做不同的事情,那么这些内核将不会访问相同的内存,并且在高速缓存行中不会具有相同的内存。

如果核心#1 使用内存栅栏,但没有其他核心访问核心#1 访问的内存,那么其他核心根本不会减慢速度。但是,如果核心 #1 写入位置 X,使用内存栅栏,然后核心 #2 尝试读取相同的位置 X,内存栅栏将确保核心 #2 丢弃位置 X 的值,如果它位于缓存,并从 RAM 中读回数据,获得与核心 #1 写入的相同数据。这当然需要时间,但这就是内存栅栏的用途。

(而不是从 RAM 中读取,如果内核共享一些缓存,那么数据将从缓存中读取。)

于 2014-09-13T12:16:56.057 回答