首页 > 解决方案 > 为什么强内存模型不会阻止 cpu 缓存?

问题描述

Joseph Albahari 在他的博客表示,即使在强内存订单 cpu(例如普通的 Intel Core-2 和 Pentium 处理器)上,

下面的程序永远不会终止,因为完整的变量缓存在 CPU 寄存器中。在 while 循环内插入对 Thread.MemoryBarrier 的调用(或锁定读取完成)可修复错误。

static void Main()
{
  bool complete = false; 
  var t = new Thread (() =>
  {
    bool toggle = false;
    while (!complete) toggle = !toggle;
  });
  t.Start();
  Thread.Sleep (1000);
  complete = true;
  t.Join();        // Blocks indefinitely
}

按照这里,这不应该发生吗?

强大的硬件内存模型是其中每条机器指令都隐含地带有获取和释放语义的模型。因此,当一个 CPU 内核执行一系列写入时,每个其他 CPU 内核都会看到这些值以与写入时相同的顺序发生变化。

我对这2个引号感到困惑,谁能给我更详细的解释?

标签: c#memory-barriers

解决方案


强大的硬件内存模型是其中每条机器指令都隐含地带有获取和释放语义的模型。因此,当一个 CPU 内核执行一系列写入时,每个其他 CPU 内核都会看到这些值以与写入时相同的顺序发生变化。

在此示例中,内存写入顺序并不重要。随着线程不断轮询,它最终会获取complete变量的更新值。

但是,这与内存和缓存有关,它们必须向所有处理器呈现相同的视图。每个 cpu 的寄存器都是私有的,不必与其他 cpu 共享它们的内容。

complete变量在线程 t 的寄存器中。任何其他处理器都无法更新此寄存器,因为它实际上没有链接到内存系统。制作变量volatile将解决问题,因为它将保留在内存中而不是注册。

下面的程序永远不会终止,因为完整的变量缓存在 CPU 寄存器中。在 while 循环内插入对 Thread.MemoryBarrier 的调用(或锁定读取完成)可修复错误。

这两个修复基本上都将变量保留在内存中以使其工作。


推荐阅读