为什么吸气剂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
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,事实证明,允许抖动假设所有非易失性变量只能由一个线程访问(非常类似于C++ 11内存模型,其中并发访问非std::atomic<>变量调用未定义的行为).在这种情况下,抖动正在优化第一个循环loop: test eax, eax; je loop(它将变量访问提升到永远不会更新的寄存器),所以很明显它永远不会终止.
第二个循环生成组件,该组件读取相对于对象指针的值,因此最终它会看到新值(尽管可能与另一个线程上的其他写入无关,因为该变量不是易失性的).由于碰巧生成的装配,这是巧合.
为第一个(无限)循环生成的x86程序集:
003B23BA test eax,eax
003B23BC je 003B23BA
Run Code Online (Sandbox Code Playgroud)
第二个(有限)循环的x86程序集:
002F2607 cmp dword ptr [eax+4],0
002F260B je 002F2607
Run Code Online (Sandbox Code Playgroud)
由于允许抖动假设非易失性变量永远不会被其他线程触及,因此您只能依赖于volatile按预期工作(即使它出现在给定的情况下,如此,因为未来的优化(或不同的CPU架构)等等可能会以难以调试的方式破坏您的代码).