C ++ 11: Безопасная двойная проверка блокировки для отложенной инициализации. Возможный?

Я прочитал много вопросов, касающихся поточно-ориентированной блокировки с двойной проверкой (для одиночных или ленивых инициалов). В некоторых потоках ответ таков: шаблон полностью нарушен, другие предлагают решение.

Итак, мой вопрос: есть ли способ написать полностью поточно-ориентированный шаблон блокировки с двойной проверкой в ​​C ++? Если так, то как это выглядит.

Мы можем принять C ++ 11, если это облегчает ситуацию. Насколько я знаю, C ++ 11 улучшил модель памяти, которая могла дать необходимые улучшения.

Я знаю, что это возможно в Java, сделав двойную проверку защищенной переменной volatile. Поскольку C ++ 11 позаимствовал большую часть модели памяти из модели Java, я думаю, что это возможно, но как?

12

Решение

Просто используйте статическую локальную переменную для лениво инициализированных синглетонов, вот так:

MySingleton* GetInstance() {
static MySingleton instance;
return &instance;
}

Стандарт (C ++ 11) уже гарантирует, что статические переменные инициализируются потокобезопасным способом, и кажется вероятным, что реализация этого по крайней мере столь же надежна и эффективна, как и все, что вы пишете сами.

Потоковая безопасность инициализации может быть найдена в §6.7.4 стандарта (C ++ 11):

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

17

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

Так как вы хотели увидеть правильную реализацию DCLP C ++ 11, вот один из них.

Поведение полностью потокобезопасно и идентично GetInstance() в ответе Гризли.

std::mutex mtx;
std::atomic<MySingleton *> instance_p{nullptr};

MySingleton* GetInstance()
{
auto *p = instance_p.load(std::memory_order_acquire);

if (!p)
{
std::lock_guard<std::mutex> lck{mtx};

p = instance_p.load(std::memory_order_relaxed);
if (!p)
{
p = new MySingleton;
instance_p.store(p, std::memory_order_release);
}
}

return p;
}
3

По вопросам рекламы [email protected]