Ceci est une ancienne révision du document !
Problème
The "Double-Checked Locking is Broken" Declaration Archive
C++ and the Perils of Double-Checked Locking Archive
Consider again pInstance = new Singleton;, the line that initializes pInstance. This statement causes three things to happen:
Step 1. Allocate memory to hold a Singleton object. Step 2. Construct a Singleton object in the allocated memory. Step 3. Make pInstance point to the allocated memory.Of critical importance is the observation that compilers are not constrained to perform these steps in this order! In particular, compilers are sometimes allowed to swap Steps 2 and 3. Why they might want to do that is a question we'll address in a moment. For now, let's focus on what happens if they do. C++ and The Perils of Double-Checked Locking: Part I Archive C++ and The Perils of Double-Checked Locking: Part II Archive
En gros, le pointeur peut être différent de null
mais pour autant l'objet peut ne pas avoir été construit si le thread est arrêté entre l'étape 2 et 3 et qu'elles sont inversées.
Solution
Double-Checked Locking is Fixed In C++11, Archive
Thread-Safe Initialization of a Singleton, Archive
Si le singleton possède un constructeur trivial :
std::atomic<Singleton*> Singleton::m_instance; std::mutex Singleton::m_mutex; Singleton* Singleton::getInstance() { Singleton* tmp = m_instance.load(std::memory_order_acquire); if (tmp == nullptr) { std::lock_guard<std::mutex> lock(m_mutex); tmp = m_instance.load(std::memory_order_relaxed); if (tmp == nullptr) { tmp = new Singleton; m_instance.store(tmp, std::memory_order_release); } } return tmp; }
Si constructeur non trivial :
class MySingleton{ public: static MySingleton& getInstance() { std::call_once(initInstanceFlag, &MySingleton::initSingleton); return *instance; } private: static MySingleton* instance; static std::once_flag initInstanceFlag; static void initSingleton() { instance= new MySingleton; } };