Я только что прочитал отличный блог C ++ и опасности двойной проверки блокировки
И я не понимаю, почему мы должны использовать первый барьер памяти в Примере 12 (как показано ниже):
Singleton* Singleton::instance () {
Singleton* tmp = pInstance;
... // insert memory barrier
if (tmp == 0) {
Lock lock;
tmp = pInstance;
if (tmp == 0) {
tmp = new Singleton;
... // insert memory barrier
pInstance = tmp;
}
}
return tmp;
}
Безопасно ли изменить его на код ниже? Почему бы и нет?
Singleton* Singleton::instance () {
if (pInstance == 0) {
Lock lock;
if (pInstance == 0) {
Singleton* tmp = new Singleton;
... // insert memory barrier
pInstance = tmp;
}
}
return pInstance;
}
Нет, это не безопасно. Если прочитать три абзаца перед примером и два после него, потенциальной проблемой является система, в которой запись в pInstance
выполняется (сбрасывается в память) в потоке B перед созданием Singleton
был покраснел Тогда поток А мог прочитать pInstance
увидеть указатель как ненулевой и вернуть его, потенциально позволяя потоку A получить доступ к Singleton
до того, как поток B закончил хранить его в памяти.
Первая промывка необходима, чтобы гарантировать, что промывка записей во время строительства Singleton
были завершены до вы пытаетесь использовать его в другой теме.
В зависимости от оборудования, на котором вы работаете, это может не быть проблемой.
Других решений пока нет …