efficace thread-safe singleton en C++
Le schéma habituel pour une classe singleton est quelque chose comme
static Foo &getInst()
{
static Foo *inst = NULL;
if(inst == NULL)
inst = new Foo(...);
return *inst;
}
Cependant, c'est ma compréhension que cette solution n'est pas thread-safe, parce que 1) Foo constructeur qui peut être appelé plus d'une fois (ce qui peut ou ne peut pas d'importance) et 2) inst peut ne pas être entièrement construit avant, il est renvoyé à un autre thread.
Une solution consiste à envelopper un mutex autour de l'ensemble de la méthode, mais je suis payer pour la surcharge de la synchronisation de temps après j'ai réellement besoin. Une alternative est quelque chose comme
static Foo &getInst()
{
static Foo *inst = NULL;
if(inst == NULL)
{
pthread_mutex_lock(&mutex);
if(inst == NULL)
inst = new Foo(...);
pthread_mutex_unlock(&mutex);
}
return *inst;
}
Est-ce la bonne façon de le faire, ou il y a des pièges, je devrais être au courant? Par exemple, il y a de l'électricité statique de l'ordre d'initialisation des problèmes qui peuvent se produire, c'est à dire inst toujours la garantie d'être NULLE la première fois getInst est appelé?
- Mais vous n'avez pas le temps de trouver un exemple et de départ jusqu'à un vote serré? Je suis frais en ce moment.
- double possible de stackoverflow.com/questions/6915/...
- Non, l'interlocuteur ne pouvais évidemment pas être dérangé, alors pourquoi devrais-je? J'ai décidé d'abandonner downvoting et la clôture des dupes, et j'ai comme l'impression d'être l'un des rares à se soucier de garder la merde hors de soi. Et vous savez, la paresse se sent bien!
- J'ai pris le temps de bien décrire mon problème, avec des extraits de code et une discussion de ce que je savais/avait essayé. Je suis désolé, je l'ai gaspillé votre temps avec "merde." 🙁
- Si vous ne vous sentez pas comme la recherche de dupes et de clôture des questions, pourquoi la peine de pointage et de gagner un mauvais karma? C'est un très bon fil sur le sujet: stackoverflow.com/questions/6915. J'ai voté pour le fermer.
- donc, I. Dispersion des réponses à travers des milliers de question est le meilleur moyen pour rendre difficile la recherche par la suite.
- Double Possible de C++ modèle de conception Singleton
Vous devez vous connecter pour publier un commentaire.
Votre solution est appelée "double vérification de verrouillage" et la façon dont vous avez écrit, il n'est pas thread-safe.
Ce Meyers/Alexandrescu papier explique pourquoi - mais que le papier est également largement méconnue. Il a commencé la " double vérification de verrouillage est dangereux en C++' meme - mais son véritable conclusion est que la double vérification de verrouillage en C++ peut être mis en œuvre en toute sécurité, il faut juste l'utilisation de barrières de mémoire dans un non-évidence.
Le papier contient des pseudo-code montrant comment utiliser les barrières de la mémoire en toute sécurité mettre en œuvre les DLCP, de sorte qu'il ne devrait pas être difficile pour vous de corriger vos mise en œuvre.
Si vous êtes à l'aide de C++11, voici une bonne façon de le faire:
Selon la nouvelle norme, il n'y a pas besoin de se soucier de ce problème plus. L'initialisation de l'objet ne seront effectués que par un seul thread, d'autres threads en attente jusqu'à ce qu'il complète.
Ou vous pouvez utiliser std::call_once. (plus d'info ici)
Herb Sutter parle de la double vérification de verrouillage dans CppCon 2014.
Ci-dessous le code que j'ai mis en œuvre en C++11, qui s'appuie sur:
vous pouvez également consulter le programme complet ici: http://ideone.com/olvK13
static Foo foo;
etreturn &foo;
l'intérieur de l'instance de la fonction serait assez;static
d'initialisation est thread-safe en C++11. Préférez référence à des pointeurs si.Utilisation
pthread_once
, qui est garanti que la fonction d'initialisation est exécutée une fois atomiquement.(Sur Mac OS X, il utilise un verrou de rotation. Ne sais pas la mise en œuvre d'autres plates-formes.)
TTBOMK, la seule garantie thread-safe façon de le faire sans verrouillage serait d'initialiser tous les singletons de votre avant vous jamais commencer une discussion.
Votre alternative est appelé "une double vérification de verrouillage".
Il pourrait exister multi-thread modèles de mémoire dans lequel il travaille, mais POSIX ne garantit pas un
ACE singleton mise en œuvre utilise un double contrôle de verrouillage de modèle pour la sécurité des threads, vous pouvez vous y reporter si vous le souhaitez.
Vous pouvez trouver le code source ici.
Ne TLS travailler ici? https://en.wikipedia.org/wiki/Thread-local_storage#C_and_C++
Par exemple,
Mais nous avons également besoin d'un moyen de supprimer de façon explicite, comme
La solution n'est pas thread-safe parce que la déclaration
peut être décomposé en deux états par le compilateur:
Ci statement1: inst = malloc(sizeof(Toto));
Statement2: inst->Foo();
Supposons qu'après l'exécution de position 1 par un seul thread changement de contexte. Et 2ème thread exécute également le
getInstance()
méthode. Puis le 2ème fil se trouve que le 'inst' pointeur n'est pas null. Donc 2ème fil sera de retour pointeur vers un objet non initialisé en tant que constructeur n'a pas encore été appelé par le 1er thread.