Outils pour utilisateurs

Outils du site


helloworld:design_pattern:singleton:cplusplus

Problème

The "Double-Checked Locking is Broken" Declaration Archive le 28/04/2020

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 du 01/07/2004 le 28/04/2020 C++ and The Perils of Double-Checked Locking: Part II Archive du 01/08/2004 le 28/04/2020

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 du 30/09/2013 le 28/04/2020

Thread-Safe Initialization of a Singleton Archive du 30/08/2016 le 28/04/2020

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::scoped_lock<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.txt · Dernière modification : 2022/07/04 10:06 de root