Вот раздел стандарта, который меня смущает: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf#page=178&zoom=auto,87,610%22
2.1. Если тип еще не инициализирован, попробуйте установить блокировку инициализации.
2.2.1. В случае неудачи проверьте, удерживает ли этот поток или любой другой поток, ожидающий завершения этого потока, блокировку.
2.2.2. Если это так, вернитесь, поскольку блокировка приведет к тупиковой ситуации. Этот поток теперь увидит состояние неполной инициализации для типа, но взаимоблокировка не возникнет.
Следующий код блокируется, когда я его тестирую, что, похоже, противоречит стандарту:
public static class Foo {
static Foo() {
var otherThread = new Thread(() => { Thread.Sleep(1000); SomeFunction(); });
otherThread.Start();
otherThread.Join();
}
public static void SomeFunction() {
}
}
class Program {
static void Main() {
Foo.SomeFunction();
}
}
Согласно стандарту, я ожидаю, что произойдет следующее:
- Основной поток берет блокировку инициализации на Foo.
- Основной поток запускает статический конструктор Foo.
- Основной поток создает otherThread и запускает его.
- otherThread начинает ждать одну секунду, таким образом гарантируя, что точка 5 произойдет раньше, чем точка 6.
- Основной поток начинает ожидать завершения otherThread.
- otherThread пытается взять блокировку инициализации на Foo и терпит неудачу, потому что основной поток удерживает блокировку.
- otherThread отказывается от выполнения статического конструктора, потому что основной поток удерживает блокировку инициализации и ожидает otherThread.
- otherThread запускает SomeFunction и успешно завершает работу.
- Основная нить возвращается.
Что здесь не так?