В С++ и опасностях блокировки с двойным проверкой, там persudo-код правильно реализует шаблон, который предлагается авторами. См. Ниже,
Singleton* Singleton::instance () {
Singleton* tmp = pInstance;
... // insert memory barrier (1)
if (tmp == 0) {
Lock lock;
tmp = pInstance;
if (tmp == 0) {
tmp = new Singleton;
... // insert memory barrier (2)
pInstance = tmp;
}
}
return tmp;
}
Мне просто интересно, может ли первый барьер памяти перемещаться прямо над оператором return?
EDIT: Другой вопрос: в связанной статье, как vidstige, указан
Технически вам не нужны полные двунаправленные барьеры. Первый барьер должно препятствовать нисходящей миграции конструкции Синглтонов (через другой поток); второй барьер должен препятствовать миграции вверх инициализации pInstances. Они называются "приобретать" и "освободить" операции и может обеспечить лучшую производительность, чем полная барьеры на оборудовании (например, Itainum), который делает различие.
В нем говорится, что второй барьер не должен быть двунаправленным, поэтому как он может препятствовать перемещению pInstance перед этим барьером? Несмотря на то, что первый барьер может предотвратить миграцию вверх, но в другом потоке все еще есть шанс увидеть неинициализированные элементы.
EDIT: Я думаю, что я почти понимаю цель первого барьера. Как отметил sonicoder, предсказание ветвления может привести к тому, что tmp будет NULL, если if вернет true. Чтобы избежать этой проблемы, должен быть обнаружен барьер, препятствующий чтению tmp взамен до чтения в if.Забастовкa >
Первый барьер сопряжен со вторым барьером для достижения синхронизации с отношением, поэтому он может двигаться вниз.
EDIT. Для тех, кто интересуется этим вопросом, я настоятельно рекомендую читать memory-barriers.txt.