Недавно я встретил следующую публикацию на веб-сайте Resharper. Это было обсуждение блокировки с двойной проверкой и имело следующий код:
public class Foo
{
private static volatile Foo instance;
private static readonly object padlock = new object();
public static Foo GetValue()
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Foo();
instance.Init();
}
}
}
return instance;
}
private void Init()
{
...
}
}
Затем сообщение утверждает, что
Если предположить, что Init() - это метод, используемый для инициализации состояния Foo, то приведенный выше код может не работать должным образом из-за модель памяти, не гарантирующая порядок чтения и записи. Как результат, вызов Init() может действительно произойти до переменной экземпляр находится в согласованном состоянии.
Вот мои вопросы:
-
Насколько я понял, модель памяти .NET(по крайней мере с версии 2.0) не требовала объявления
instance
какvolatile
, так какlock
обеспечивал бы полный забор памяти. Разве это не так, или я был дезинформирован? -
Является ли переупорядочение чтения/записи только наблюдаемым в отношении нескольких потоков? Я понимал, что в одном потоке побочные эффекты будут в последовательном порядке и что
lock
на месте помешает любому другому потоку замечать что-то недопустимое. Я тоже вне базы?