约瑟夫·阿尔巴哈里(Joseph Albahari)在他的博客here中表示,即使使用强大的内存顺序CPU(例如普通的Intel Core-2和Pentium处理器),
以下完整程序永远不会终止,因为complete变量被缓存在 CPU寄存器。在内部插入对Thread.MemoryBarrier的调用 while循环(或锁定阅读完成)可修复错误。
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
}
根据here,这应该不会发生吗?
强大的硬件内存模型是其中每条机器指令都隐式带有获取和释放语义的模型。结果,当一个CPU内核执行一系列写操作时,每个其他CPU内核都会看到这些值以它们被写入的顺序改变。
我对这两个引号感到困惑,有人可以给我更详细的解释吗?
答案 0 :(得分:0)
强大的硬件内存模型是其中每条机器指令都隐式带有获取和释放语义的模型。结果,当一个CPU内核执行一系列写操作时,每个其他CPU内核都会看到这些值以它们被写入的顺序改变。
在此示例中,内存写入顺序并不重要。随着线程不断轮询,最终它将获取complete
变量的更新值。
但是,这与内存和缓存有关,必须向所有处理器提供相同的视图。每个cpu的寄存器都是私有的,不必与其他cpus共享它们的内容。
complete
变量位于线程t的寄存器中。由于该寄存器实际上未链接到内存系统,因此任何其他处理器都无法更新该寄存器。设置变量volatile
将解决该问题,因为它将保留在内存中而不进行注册。
以下完整程序永远不会终止,因为complete变量已缓存在CPU寄存器中。在while循环内插入对Thread.MemoryBarrier的调用(或锁定读取完成)可修复该错误。
这两个修复程序基本上都将变量保留在内存中以使其起作用。