Outils pour utilisateurs

Outils du site


helloworld:design_pattern:singleton:cplusplus

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;
  }
};
helloworld/design_pattern/singleton/cplusplus.1522003384.txt.gz · Dernière modification : 2018/03/25 20:43 de root