c# - 为什么强内存模型不会阻止 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个引号感到困惑,谁能给我更详细的解释?
解决方案
强大的硬件内存模型是其中每条机器指令都隐含地带有获取和释放语义的模型。因此,当一个 CPU 内核执行一系列写入时,每个其他 CPU 内核都会看到这些值以与写入时相同的顺序发生变化。
在此示例中,内存写入顺序并不重要。随着线程不断轮询,它最终会获取complete
变量的更新值。
但是,这与内存和缓存有关,它们必须向所有处理器呈现相同的视图。每个 cpu 的寄存器都是私有的,不必与其他 cpu 共享它们的内容。
该complete
变量在线程 t 的寄存器中。任何其他处理器都无法更新此寄存器,因为它实际上没有链接到内存系统。制作变量volatile
将解决问题,因为它将保留在内存中而不是注册。
下面的程序永远不会终止,因为完整的变量缓存在 CPU 寄存器中。在 while 循环内插入对 Thread.MemoryBarrier 的调用(或锁定读取完成)可修复错误。
这两个修复基本上都将变量保留在内存中以使其工作。
推荐阅读
- java - java.lang.ClassCastException:java.util.Arrays$ArrayList 无法在 DAO 中强制转换为 java.lang.Integer
- sql - 如何使用多外键表编写此查询以获得精确值?
- c - 当我在编译时静态链接库时,如何更改 C ncurses 的 ESCDELAY 值?
- c - 使用 libcurl 的 SSL 连接
- c++ - 在带有 QAbstractTableModel 的 Qt 5.14.1 上未定义对“_imp____类名____虚拟方法”的引用
- python-3.x - 相当于按Ctrl+S保存文本文件的python代码
- email - 什么是快速搜索定义的电子邮件范围的好方法?
- node.js - 如何防止将建议操作转换为文本?
- sql - sql server - 从联接更新表的有效方法
- google-calendar-api - Google Calendar API 重复事件重置