Подтвердить что ты не робот

Эрик Липперт и Нил Гафтер С# Головоломка

Эта головоломка была представлена ​​в NDC 2010. Там есть ссылки на видео, но все они сломаны. Я не понимаю поведения этой программы; почему он висит?

class Woot
{
    private static float PI;
    private static bool initialized = doInitialize();

    private static bool doInitialize()
    {
        if (!initialized)
        {
            var thread = new Thread(() => { PI = 3.14f; });
            thread.Start();
            thread.Join(); // here
        }
        return true;
    }

    public static void Main(string[] args)
    {
        Console.WriteLine(PI);
    }
}

Каков результат этой программы? Это:

  • 3,14
  • 0
  • Вызывает исключение
  • Ничего из вышеперечисленного
4b9b3361

Ответ 1

Я считаю, что проблема вызвана статичным иналитаризатором поля. Я заметил, что новый поток запускается только тогда, когда выполняется doInitialize (несмотря на то, что thread.Start() вызывается) - , поэтому я полагаю, что CLR блокирует другие потоки, чтобы избежать параллельного доступа/двойной инициализации поля.

Подводя итог: недавно созданный поток не запускается CLR, чтобы избежать параллельного доступа, но основной поток инициализации ожидает выполнения дочернего потока, что означает тупик.

Edit

@Себастьян предложил (в комментарии) ссылку, которая может подтвердить мою теорию: http://blogs.msdn.com/b/pfxteam/archive/2011/05/03/10159682.aspx

Ответ 2

doInitialize выполняется, когда статический тип сконструирован, а затем останавливается до тех пор, пока не завершится поток, который устанавливает PI.

Тем не менее поток, который пытается установить PI, не может быть запущен до тех пор, пока тип не будет инициализирован, что произойдет только после завершения инициализации (статический конструктор и статические инициализаторы) - что еще не произошло, как описано выше.

Таким образом, программные взаимоблокировки.

См. также этот ответ Эрика Липперта.

Ответ 3

Нить никогда не закончится, поэтому thread.Join() никогда не вернется. doInitialize() выполняется из статического конструктора. В статическом конструкторе мы пытаемся установить статическое свойство, но мы не можем получить доступ к статическому свойству, если статический конструктор не будет завершен.  гонки