Двойная проверка блокировки для общих указателей

Отказ от ответственности: Я пришел из Java, и поэтому не имею понятия о том, как работает множество внутренних компонентов C ++ (и связанных с ними библиотек).

Я прочитал достаточно, чтобы знать, что двойная проверка блокировки — это зло, и для правильной и безопасной реализации одноэлементного шаблона требуются соответствующие инструменты.

Я полагаю, что следующий код может быть небезопасным, с учетом переупорядочения компилятора и назначения неинициализированных объектов, но я не уверен, что мне не хватает чего-то, чего я не понимаю в языке.

typedef boost::shared_ptr<A> APtr;

APtr g_a;
boost::mutex g_a_mutex;
const APtr& A::instance()
{
if (!g_a)
{
boost::mutex::scoped_lock lock(g_a_mutex);
if (!g_a)
{
g_a = boost::make_shared<A>();
}
}

return g_a;
}

Я считаю, что фактический код скомпилирован под C ++ 03.

Эта реализация небезопасна? Если так, то как?

4

Решение

Все это абсолютно необходимо в современном C ++. Синглтон код должен быть таким же простым для всех, кроме динозавров:

A& A::instance() {
static A a;
return a;
}

100% потокобезопасность в C ++ 11 и выше.

Тем не менее, я должен сделать следующее обязательное заявление: синглтоны — злой антипаттерн, и их следует запретить навсегда.

Поток безопасности оригинального кода

Да, предоставленный код небезопасен. Поскольку чтение выполняется вне мьютекса, вполне возможно, что изменения в g_a сам было бы видно, но не то, что модификации объекта g_a указывает на. В результате поток обойдет блокировку мьютекса и вернет указатель на не построенный объект.

1

Другие решения

Да, дважды проверенный шаблон блокировки небезопасен в архаичных языках. Я не могу сделать ничего лучше, чем объяснение в Что не так с этим исправлением для двойной проверки блокировки?:

Очевидно, проблема заключается в назначении экземпляра строки — компилятор может выделить объект и затем назначить ему указатель, ИЛИ установить указатель на то место, где он будет размещен, а затем выделить его.

Если вы использовали C ++ 11 std::shared_ptrВы могли бы использовать atomic_load а также atomic_store на объекте общего указателя, который гарантированно правильно скомпонован друг с другом и с мьютексами; но если вы используете C ++ 11, вы можете просто использовать динамически инициализированный static переменная, которая гарантированно является поточно-ориентированной.

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector