std::shared_ptr fil de sécurité
J'ai lu que
"Plusieurs threads peuvent lire ou écrire simultanément différents
shared_ptr objets, même lorsque les objets sont des copies qui partagent
propriété". (MSDN: Fil de Sécurité dans la Bibliothèque C++ Standard)
Est-ce à dire que le changement de shared_ptr objet est sûr ?
Pour un exemple, le code suivant considérés comme sûrs:
shared_ptr<myClass> global = make_shared<myClass>();
...
//In thread 1
shared_ptr<myClass> private = global;
...
//In thread 2
global = make_shared<myClass>();
...
Puis-je être sûr dans ce cas que le thread 1 private
aura la valeur d'origine de global
ou la nouvelle valeur qui le thread 2 affecté, mais de toute façon il va avoir un valide shared_ptr myClass?
==EDIT==
Juste pour expliquer ma motivation. Je veux avoir un pointeur partagé de tenir ma configuration et j'ai un pool de threads pour gérer les demandes.
donc global
est la configuration globale.
thread 1
est de prendre la configuration actuelle comme il commence à traiter une demande.
thread 2
est la mise à jour de la configuration. (uniquement s'appliquer aux futures demandes)
Si c'est un travail, je peux mettre à jour la configuration de cette façon sans le casser dans le moyen de traitement de la demande.
- Plusieurs threads peuvent lire ou écrire simultanément différents shared_ptr objets, Le mot clé est différentes
- C'était mon idée initiale, mais il semble comme une redondant chose à dire. bien sûr, vous pouvez lire et à écrire à des objets différents...
- Il n'est pas "offcourse". Le smart pointeur pointe vers une commune helper object mise en œuvre du comptage de référence. Avec une naïveté de la mise en œuvre du comptage de référence sur l'objet d'assistance qui pourrait aller mal. Pourtant, je pense que votre question est bonne et la réponse définitive la plupart de bienvenue.
- J'ai étendu mon entreprise shared_ptr mise en œuvre à l'appui de weak. Et je peux vous dire, il n'y a pas de façon de le faire thread-safe autres que par l'utilisation complète de sections critiques dans des méthodes qui manipulent le nombre de références. (la partie de la clé est le pluriel ici) Normes shared_ptr utilisation atomique inc/dec et cmp/xch dans la méthode release() pour vérifier contre 0 avant de les supprimer. Ce n'est pas thread-safe en raison de la 2ème ref nombre (la faiblesse de comptage ref). Un faible ref pourrait tourner partagé après le test est réussi, et vous avez un ballants. boom.
- c'est pourquoi la
weak_ptr::lock()
fonction utilise compare-and-swap, de sorte qu'il peut savoir qu'il n'a pas si un autre thread décrémenté le décompte à zéro. Soit je suis malentendu exactement ce que vous entendez par "thread-safe" ou votre commentaire est incorrect. - Je pense que vous avez compris sur place. Il a été un moment depuis que j'ai pensé à tout cela, alors je suis allé vérifier de nouveau ici: boost.org/doc/libs/1_38_0/boost/detail/... . J'ai le sentiment de l'astuce pour le faire fonctionner est ici:
#weak + (#shared != 0)
le faible nombre est un peu spécial, et permet de vérifier avant de shared_count destruction dansweak_release()
. mon idée naïve de na pas mettre en œuvre ce truc donc atomicality ne pourrais pas être exerced dans ce test. private
est un mot-clé, il ne peut pas être utilisé comme un nom de variable
Vous devez vous connecter pour publier un commentaire.
Ce que vous êtes en train de lire n'est pas ce que vous pensez que cela signifie. Tout d'abord, essayez la page msdn pour shared_ptr lui-même.
Faites défiler vers le bas dans la section "Remarques" et vous aurez de la viande de la question. Fondamentalement, un
shared_ptr<>
points à un "bloc de contrôle" qui est la façon dont il garde la trace de combien deshared_ptr<>
objets sont réellement pointant vers la "Vraie" objet. Donc, quand vous faites cela:Alors qu'il est à seulement 1 appel à allouer de la mémoire ici via
make_shared
, il y a deux "logiques" de blocs que vous ne devriez pas traiter le même. L'un est leint
qui stocke la valeur réelle, et l'autre est le bloc de contrôle, qui stocke toutes lesshared_ptr<>
"magique" qui le fait fonctionner.Il n'est que le bloc de contrôle de lui-même qui est thread-safe.
Je l'ai mis sur sa propre ligne pour mettre l'accent. Le contenu de la
shared_ptr
ne sont pas thread-safe, ni est écrit à la mêmeshared_ptr
instance. Voici quelque chose à démontrer ce que je veux dire:C'est très bien, en fait, vous pouvez le faire dans toutes les discussions comme beaucoup que vous le souhaitez. Et puis quand
local_instance
est détruite (par sortir du champ d'application), il est également thread-safe. Quelqu'un peut accéder àglobal_instance
et il ne fera pas une différence. L'extrait de code que vous avez retirées à partir de msdn signifie fondamentalement "l'accès au bloc de contrôle est thread-safe" de sorte que les autresshared_ptr<>
instances peuvent être créés et détruits sur différents threads autant que nécessaire.C'est très bien. Il sera affecter la
global_instance
objet, mais seulement indirectement. Le bloc de contrôle de pointe pour sera décrémenté, mais fait dans un thread-safe façon.local_instance
n'aura plus de point pour le même objet (ou d'un bloc de contrôle) commeglobal_instance
n'.Ce n'est presque certainement pas très bien si
global_instance
est accessible à partir de tous les autres threads (qui vous dites que vous êtes en train de faire). Il a besoin d'un verrou si vous faites cela parce que vous écrivez là oùglobal_instance
vie, pas seulement de la lecture. Donc, l'écriture à un objet à partir de plusieurs threads est mauvais, sauf que vous avez gardé par un verrou. De sorte que vous pouvez lire à partir deglobal_instance
l'objet par l'attribution deshared_ptr<>
objets, mais vous ne pouvez pas écrire.La valeur de
a
est pas défini. Il pourrait être de 7, ou il peut être de 3, ou il pourrait être quelque chose d'autre aussi. Le fil de sécurité de lashared_ptr<>
cas s'applique uniquement à la gestion deshared_ptr<>
les instances qui ont été initialisé les uns des autres, et non pas ce qu'ils sont en pointe.De souligner ce que je veux dire, regardez ceci:
Un
shared_ptr<>
est un mécanisme pour assurer que plusieurs objet propriétaires de garantir que l'objet est détruit, pas un mécanisme pour s'assurer de multiples fils peut accéder à un objet correctement. Vous avez encore le besoin d'un mécanisme de synchronisation pour l'utiliser en toute sécurité dans plusieurs threads (comme std::mutex).La meilleure façon de penser de l'OMI est que
shared_ptr<>
permet de s'assurer que des copies multiples pointant vers la même mémoire n'ont pas de problèmes de synchronisation pour lui-même, mais ne fait rien pour l'objet pointé. Le traiter comme ça.new
). Il y a un seulmalloc
et 2 mise en place de nouvelles à l'aide demake_shared
.priv_ptr
ou quelque chose, et tous les autres à la suite, que le schéma de nommage.private
dans une telle réponse, j'ai finalement fixé, a déclaré nom de la variable. J'ai aussi fixéglobal
àglobal_instance
pour plus de clarté et de cohérence.in main, in thread1
n'est-il pas dangereux pour lire à partir d'mondiale, tandis que d'autres thread d'écriture à elle, pourrait-il être déchiré de lecture/écriture de là? Pas sûr que la construction est atomiquemain
action se passe, ALORS vous lancer le thread, ce qui bien sûr peut-être pas le droit. Je vais le modifier pour le rendre plus clair c'est ce que je veux dire. Leglobal_instance
doit être entièrement construit avant de l'utiliser dans un autre thread.À ajouter à ce que Kevin a écrit, le C++14 spec a un soutien supplémentaire pour l'accès à shared_ptr objets eux-mêmes:
Donc, si vous n':
il va être thread-safe.
_explicit
formes, droit?... = atomic_load_explicit(&global, std::memory_order_acquire);
etatomic_store_explicit(&global, make_shared<myClass>(), std::memory_order_release);
. Sur fortement ordonné comme les systèmes x86, ces formes explicites ne nécessitent même pas les barrières de la mémoire, d'où l'utilisation par défaut (avecseq_cst
) serait.Il signifie que vous aurez un valide
shared_ptr
, et une pièce de comptage de référence.Vous décrivez une situation de concurrence entre les 2 fils qui sont d'essayer de lire/d'attribuer à la même variable.
Parce que c'est un comportement indéfini en général (il n'a de sens que dans le contexte et le calendrier du programme individuel)
shared_ptr
ne gère pas que.Les opérations de lecture ne sont pas sujettes à des courses entre eux, par conséquent, il est sûr de partager la même instance de la shared_ptr entre les threads, tant que tous les threads utilisent const méthodes (ce qui inclut la création de copies de celle-ci). Dès qu'un thread utilise non-const méthode (comme dans "point à un autre objet") une telle utilisation n'est plus "thread-safe".
L'OP n'est pas thread-safe et nécessiterait l'utilisation de la atomique en charge dans le thread 1. atomiques et les stocker dans le thread 2 (section 2.7.2.5 en C++11) pour le rendre thread-safe.
Le mot clé de MSDN texte est en effet différents shared_ptr objets, comme déjà dit dans les réponses précédentes.
Je pense que pour l'instant les réponses à cette question sont trompeuses à l'égard de scénario décrit. J'ai un scénario semblable à celle décrite dans la question. Tous les autres threads ont (besoin) juste un accès en lecture seule à la configuration actuelle qui est réalisé à travers:
Aucun de ces threads à modifier le contenu de la
MyConfig
objet. Ref nombre desp_global
est incrémenté pour chaque exécution de la ligne ci-dessus.Thread 1, périodiquement réinitialise le
sp_global
pour certains une autre instance de la configuration:Ce devrait être aussi sûr. Il définit la ref nombre de
sp_global
à 1, et lesp_global
maintenant les points à la dernière configuration, tout comme avec toutes les nouvelles copies locales. Donc, si je ne suis pas manque quelque chose ici, ce devrait être totalement thread-safe.et la sortie