核心 1 的 L1D 缓存中的缓存线仍处于共享状态
这是违反 MESI 的场景的一部分。在核心 2 发送的 RFO 完成之前,存储无法提交,因此核心 1 的行处于无效状态。
不过,在您的示例中,它实际上并不是一个“中间”步骤。如果没有同步,则无法将您的不可能场景与仅在线路无效之前发生核心 1 的负载区分开来。即核心 1 的加载可以在全局顺序中出现在核心 2 的存储之前。
存储在本地执行之后才变得全局可见(它们必须退出,然后存储队列可以将它们提交到 L1D),并且 x86 的内存模型允许 StoreLoad 重新排序,因此可以延迟存储(隐藏在私有存储中) queue) 直到稍后由核心 2 加载后变为全局可见。(有关内存重新排序的更多背景信息以及 StoreLoad 重新排序的含义,请参阅 Jeff Preshing 的Memory Barriers Are Like Source Control Operations )。
在 MESI(以及 MESIF 或 MOESI 等所有变体)中,如果一个高速缓存有一条处于 E 或 M 状态的行,则没有其他高速缓存可以拥有该行的副本。MESI 维基百科文章中的状态表非常清楚地说明了这一点:如果一个缓存具有 E 或 M 状态,则其他缓存都具有无效。
两个缓存永远不可能同时拥有具有不同数据的行的有效副本。这就是缓存一致的含义,阻止这种情况发生是 MESI 协议的重点。
如果一个核心想要修改一个高速缓存行,它会获得该行的独占所有权,因此没有其他核心可以观察到陈旧的值。这必须在商店可以提交到 L1D之前发生。存储队列的存在是为了隐藏 Read-For-Ownership 的延迟(除其他外),但存储队列中的数据尚未提交到 L1D。(相关:当不同的 CPU 内核在没有同步的情况下写入同一个 RAM 地址时会发生什么?关于存储队列的更多信息)。
顺便说一句,让我们假设它[mem]
是自然对齐的,因此对其的加载/存储是原子的(由 x86 架构保证)。 为什么在 x86 上对自然对齐的变量进行整数赋值是原子的?.
多级缓存和修改行
使用多级缓存,脏缓存行可以向上传播。所以一条线可以在同一个核心的L1D和L2处于Modified状态。这很好,因为来自 L1D 的回写通过 L2。
据我了解,英特尔 CPU 中的共享包容性 L3 高速缓存不必回写到 DRAM,就可以将高速缓存线的副本共享给多个内核。因此,就普通/简单的 MESI 而言,将 L3 视为后备存储,而不是 DRAM。
在多插槽系统上进行这项工作很棘手;我不确定是否设置好了,因此套接字中的 L3 只能缓存与连接到该套接字的 DRAM 相对应的物理地址。在任何情况下,监听请求都会在 L3 缓存未命中时在套接字之间发送,并且您可以配置许多复杂的设置来在 Xeon 系统上进行调整。(例如,请参阅有关 Haswell Xeon 的 Anandtech 文章。)