为什么方法调用将非易失性变量的值刷新到主线程?

为什么吸气剂Val碰巧模拟了场val波动?

我假设利用方法调用不是保持变量volatile的可靠方法。

(要试用它,构建版本并直接执行而不需要调试器。)

 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 } } 

好吧,事实certificate,允许抖动假设所有非易失性变量只能由一个线程访问 (非常类似于C ++ 11内存模型,其中对非std::atomic<>变量的并发访问调用undefined行为)。 在这种情况下,抖动优化第一个循环进入loop: test eax, eax; je loop 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)架构等)可能会以难以调试的方式破坏您的代码。