为什么吸气剂Val
碰巧模拟了该领域的波动性val
?
我假设利用方法调用并不是保持变量易失性的可靠方法。
(要尝试一下,请构建发布并直接执行,无需调试器。)
class Program
{
private int val = 0;
public int Val { get { return val; } }
public static void Main()
{
var example = new Program();
Task.Run(() => example.val++);
while (example.val == 0) ; // Hangs if val is not volatile
while (example.Val == 0) ; // Never seems to hang
}
}
好吧,原来允许抖动假设所有非易失性变量只能由一个线程访问 http://msdn.microsoft.com/en-us/library/x13ttww7.aspx(很像在 C++11 内存模型中,并发访问非std::atomic<>
变量调用未定义的行为)。在这种情况下,抖动将第一个循环优化为loop: test eax, eax; je loop
(它将变量访问提升到一个永远不会更新的寄存器中),所以显然它永远不会终止。
第二个循环生成读取相对于对象指针的值的程序集,因此最终它会看到新值(尽管相对于另一个线程上的其他写入可能是乱序的,同样是因为该变量不是易失性的)。这是由于碰巧生成的程序集而巧合的。
为第一个(无限)循环生成的 x86 程序集:
003B23BA test eax,eax
003B23BC je 003B23BA
第二个(有限)循环的 x86 汇编:
002F2607 cmp dword ptr [eax+4],0
002F260B je 002F2607
由于允许抖动假设非易失性变量永远不会被其他线程触及,你只能依靠volatile
按预期工作(即使在给定的情况下,就像这样,因为未来的优化(或不同的 CPU 架构等)可能会以难以调试的方式破坏您的代码)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)