Принудительный .NET, многопоточная изменчивая ошибка оптимизации - PullRequest
0 голосов
/ 23 мая 2018

Я пытаюсь воспроизвести ошибку, описанную в CLR через C # .Когда следующий код скомпилирован с оптимизацией, переменная 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);
}

Это действительно то, что происходит (как на x86, так и на 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);
}

Теперь ошибка исчезлаи приложение закрывается, как будто оптимизация не произошла.

Main: letting worker run for 5 seconds
Main: waiting for worker to stop
Worker: stopped when x=130084144

Почему добавление Console.Write исправляет эту ошибку?

1 Ответ

0 голосов
/ 23 мая 2018

Код внутри Console.Write может изменить значение статического поля.Это не так, но JIT не знает этого.Поэтому он должен генерировать код для загрузки статического поля на каждой итерации.

Этого же эффекта можно добиться, вызвав пустой метод, для которого установлен флаг no inlining.Это черный ящик для JIT.

JIT может проанализировать весь код, который может быть вызван транзитивно, и сделать вывод, что статическое поле не изменится.Но это не реализовано в JIT.

...