2

让我解释一下我的理解,并请您确认其正确性或纠正我:

  1. 有一个 MESI 协议允许有效的缓存一致性(https://en.wikipedia.org/wiki/MESI_protocol)。这是最先进的机制。
  2. 对于单个处理器的多个内核,MESI 通过在处理器内核之间共享的 L3 高速缓存运行。
  3. 对于多个处理器(没有共享 L3),MESI 通过主存储器运行。
  4. 当使用由多个线程读写的全局变量时,volatile类型说明符用于防止不需要的优化以及防止缓存在寄存器中(不是在 L1-3 缓存中)。因此,如果值不在寄存器中,而是在高速缓存或主内存中,MESI 将尽其所能让线程看到正确的全局值。
4

1 回答 1

2

对于单个处理器的多个内核,MESI 通过在处理器内核之间共享的 L3 高速缓存运行。

MESI 在所有缓存级别上运行。在某些处理器设计中,L3 高速缓存充当核心之间的高效“交换机”。例如,如果 L3 缓存是包容性的,并且将所有内容保存在任何 CPU 的 L1 或 L2 缓存中,那么只要知道某物不在 L3 缓存中就足以知道它不在任何其他内核的缓存中。这可以减少所需的窥探量。不过,这些都是复杂的优化。

对于多个处理器(没有共享 L3),MESI 通过主存储器运行。

我不确定你在这里想说什么,但它似乎与任何真实的东西都不相符。MESI 在缓存之间运行。内存不是缓存,因此不需要参与 MESI 协议。

您可能意味着对于没有 L3 高速缓存的 CPU,L2 高速缓存间 MESI 流量发生在与连接到主存储器的 CPU 总线相同的 CPU 总线上。在 CPU 具有片上内存控制器之前,这对于一些多芯片 CPU 设计来说是正确的。但是今天,大多数笔记本电脑/台式机多核 CPU 都带有内存控制器,因此连接到内存的总线只连接到内存。所以那里没有 MESI 流量。如果数据在一个核心的二级缓存中并且必须到达另一个核心的二级缓存,它不会越过内存。(想想内核和内存控制器的拓扑结构,那太疯狂了。)

当使用由多个线程读写的全局变量时,volatile 类型说明符用于防止不需要的优化以及防止缓存在寄存器中(不是在 L1-3 缓存中)。

我知道没有一种语言是这样的。在 C/C++ 中肯定不是这样,volatile因为信号不是多线程(至少在具有明确定义的多线程 API 的平台上)。对于像 Java 这样volatile具有与寄存器无关的特定语言语义的事物而言,情况并非如此。

因此,如果值不在寄存器中,而是在高速缓存或主内存中,MESI 将尽其所能让线程看到正确的全局值。

这在硬件/汇编程序级别可能是正确的。这就是寄存器存在的地方。但在实践中,这并不是因为 MESI 使内存缓存保持一致,而现代 CPU 有其他优化会产生相同类型的问题。例如,CPU 可能会预取读取或延迟写入乱序。因此,除了 MESI 之外,您还需要诸如内存屏障之类的东西。当然,这非常特定于平台。

您可以将 MESI 视为一种优化。您仍然必须执行平台要求的任何操作才能使线程间内存可见性正常工作。但是 MESI 极大地减少了这项工作。

例如,如果没有 MESI,您可能有一个设计,其中数据从一个内核传输到另一个内核的唯一方法是先写入主存,然后等待写入完成,然后再从主存读取。那将是一场彻头彻尾的灾难。首先,您最终不得不将内容刷新到主内存,以防另一个线程需要它。其次,所有这些流量都会扼杀常规的内存流量。呸。

于 2016-02-19T17:57:56.590 回答