强制.NET,多线程volatile优化错误

Ban*_*San 2 .net c# multithreading volatile

我试图通过C#重现CLR中描述的错误.当使用优化编译以下代码时,s_stopWorker仅检查变量一次(并且是false),因此应用程序永远不会终止.

private static bool s_stopWorker;

public static void Main()
{
    Console.WriteLine("Main: letting worker run for 5 seconds");
    var t = new Thread(Worker);
    t.Start();
    Thread.Sleep(5000);
    s_stopWorker = true;
    Console.WriteLine("Main: waiting for worker to stop");
    t.Join();
}

private static void Worker(object o)
{
    var x = 0;
    while (!s_stopWorker) x++;
    Console.WriteLine("Worker: stopped when x={0}", x);
}
Run Code Online (Sandbox Code Playgroud)

这确实是发生了什么(在x86和x64上,与本书相反).

如果我突然放入Console.Write,while那么优化就不会再发生了.

private static bool s_stopWorker;

public static void Main()
{
    Console.WriteLine("Main: letting worker run for 5 seconds");
    var t = new Thread(Worker);
    t.Start();
    Thread.Sleep(5000);
    s_stopWorker = true;
    Console.WriteLine("Main: waiting for worker to stop");
    t.Join();
}

private static void Worker(object o)
{
    var x = 0;
    while (!s_stopWorker)
    {
        Console.Write(string.Empty);  // <-- Added line
        x++;
    }
    Console.WriteLine("Worker: stopped when x={0}", x);
}
Run Code Online (Sandbox Code Playgroud)

现在bug已经消失,应用程序退出就好像没有发生优化一样.

Main: letting worker run for 5 seconds
Main: waiting for worker to stop
Worker: stopped when x=130084144
Run Code Online (Sandbox Code Playgroud)

为什么添加Console.Write修复此错误?

usr*_*usr 5

里面的代码Console.Write可以改变静态字段的值.它没有,但JIT不知道.因此它必须生成代码以在每次迭代时加载静态字段.

您可以通过调用设置了无内联标志的空方法来实现相同的效果.这是JIT的黑盒子.

JIT 可以分析可能被传递和结束的所有代码,静态字段不会改变.但这并没有在JIT中实现.