Est l’implémentation suivante, à l’aide de l’initialisation tardive, de thread-safe Singleton (Meyers Singleton) ?
Si non, pourquoi et comment le rendre thread safe ?
Est l’implémentation suivante, à l’aide de l’initialisation tardive, de thread-safe Singleton (Meyers Singleton) ?
Si non, pourquoi et comment le rendre thread safe ?
En C++11, il est thread-safe. Selon la norme, §6.7 [stmt.dcl] p4
:
Si le contrôle d'entrée la déclaration simultanément tandis que la variable est initialisée, l' exécution en simultané doit attendre pour l'achèvement de la phase d'initialisation.
Grâce à @Mankarse pour le signaler.
En C++03, ce code n'est pas thread-safe.
Il y a un article par Meyers, qui traite de thread-safe implémentations du modèle (ainsi que beaucoup d'autres sur le net):
Pour répondre à votre question de savoir pourquoi il n'est pas thread-safe, ce n'est pas parce que le premier appel d' instance()
doit appeler le constructeur de Singleton s
. Pour être thread-safe cela devrait se produire dans une section critique, mais il n'est pas obligatoire dans la norme qu'une section critique (de la standard à ce jour est totalement silencieux sur les threads). Les compilateurs souvent de mettre en œuvre ce à l'aide d'une simple vérification et de l'incrément de static boolean - mais pas dans une section critique. Quelque chose comme le pseudo-code suivant:
static Singleton& instance()
{
static bool initialized = false;
static char s[sizeof( Singleton)];
if (!initialized) {
initialized = true;
new( &s) Singleton(); // call placement new on s to construct it
}
return (*(reinterpret_cast<Singleton*>( &s)));
}
Voici donc un simple thread-safe Singleton (pour Windows). Il utilise un simple wrapper de classe pour Windows CRITICAL_SECTION objet, de telle sorte que nous puissions avoir le compilateur initialiser automatiquement l' CRITICAL_SECTION
avant main()
est appelé. Idéalement, un vrai RAII section critique de la classe serait utilisé pour traiter les exceptions qui peuvent se produire lorsque la section critique est de la tenue, mais c'est au-delà de la portée de cette réponse.
L'opération fondamentale est que lorsqu'une instance d' Singleton
est demandé, un verrou, le Singleton est créé s'il doit l'être, alors le verrou est libéré et le Singleton de référence retourné.
#include <windows.h>
class CritSection : public CRITICAL_SECTION
{
public:
CritSection() {
InitializeCriticalSection( this);
}
~CritSection() {
DeleteCriticalSection( this);
}
private:
// disable copy and assignment of CritSection
CritSection( CritSection const&);
CritSection& operator=( CritSection const&);
};
class Singleton
{
public:
static Singleton& instance();
private:
// don't allow public construct/destruct
Singleton();
~Singleton();
// disable copy & assignment
Singleton( Singleton const&);
Singleton& operator=( Singleton const&);
static CritSection instance_lock;
};
CritSection Singleton::instance_lock; // definition for Singleton's lock
// it's initialized before main() is called
Singleton::Singleton()
{
}
Singleton& Singleton::instance()
{
// check to see if we need to create the Singleton
EnterCriticalSection( &instance_lock);
static Singleton s;
LeaveCriticalSection( &instance_lock);
return s;
}
L'homme qui a beaucoup de merde de "faire mieux".
Les principaux inconvénients de cette mise en œuvre (si je n'ai pas laissé de quelques bugs passer à travers) est:
new Singleton()
lancers, la serrure ne sera pas publié. Ceci peut être résolu en utilisant une vraie RAII verrouillage de l'objet au lieu de la simple que j'ai ici. Cela peut aussi aider à rendre les choses portable si vous utilisez quelque chose comme coup de pouce pour fournir une plate-forme indépendante de l'enveloppe pour le verrouiller.main()
est appelé - si vous appelez avant (comme dans un objet statique de l'initialisation) des choses peut ne pas fonctionner en raison de l' CRITICAL_SECTION
pourrait ne pas être initialisé.En regardant la prochaine norme (section 6.7.4), il explians comment l’initialisation locale statique est thread-safe. Donc une fois que l’article de la norme largement implémentée, Singleton de Meyer sera la mise en œuvre préférée.
Je suis en désaccord avec beaucoup de réponses déjà. La plupart des compilateurs implémentent déjà l’initialisation statique de cette façon. La seule exception notable est Microsoft Visual Studio.
Est la suite de la mise en œuvre [ ... ] "thread-safe"?
Sur la plupart des plates-formes, ce n'est pas thread-safe. (Ajout de l'avertissement habituel expliquant que la norme C++ ne sait pas à propos des threads, donc, légalement, il ne dit pas si elle est ou non).
Si non, pourquoi [...]?
La raison pour laquelle il n'est pas, c'est que rien n'empêche plus d'un fil à partir de tout en exécutant
s
' constructeur.comment faire thread-safe?
"C++ et les Dangers de la Double vérification de Verrouillage" par Scott Meyers et Andrei Alexandrescu est un très bon traité sur le sujet de thread-safe singletons.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.