Как правильно использовать Double-Checked Locking с барьером памяти в C++?

Я только что прочитал отличный блог 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;
    }

1 ответ

Решение

Нет, это не безопасно. Если прочитать три абзаца перед примером и два после него, потенциальной проблемой является система, в которой запись в pInstance выполняется (сбрасывается в память) в потоке B перед созданием Singleton был покраснел Тогда поток А мог прочитать pInstanceувидеть указатель как ненулевой и вернуть его, потенциально позволяя потоку A получить доступ к Singleton до того, как поток B закончил хранить его в памяти.

Первая промывка необходима, чтобы гарантировать, что промывка записей во время строительства Singleton были завершены, прежде чем пытаться использовать его в другой теме.

В зависимости от оборудования, на котором вы работаете, это может не быть проблемой.

Другие вопросы по тегам