117 votes

Existe-t-il un équivalent non atomique de std :: shared_ptr? Et pourquoi n'y en a-t-il pas <memory> ?

C'est un peu une deuxième partie de la question, tous les propos de l'atomicité de l' std::shared_ptr:

1. Aussi loin que je peux dire, std::shared_ptr est le seul pointeur intelligent en <memory> c'est atomique. Je me demandais si il y a un non-atomique version de std::shared_ptr disponible (je ne peux pas voir quoi que ce soit dans <memory>, donc je suis également ouvert à toutes les suggestions en dehors de la norme, comme ceux de Boost). Je connais boost::shared_ptr est également atomique (si BOOST_SP_DISABLE_THREADS n'est pas défini), mais peut-être qu'il y a une autre alternative? Je suis à la recherche de quelque chose qui a la même sémantique que l' std::shared_ptr, mais sans l'atomicité.

2. Je comprends pourquoi std::shared_ptr est atomique; c'est plutôt agréable. Cependant, il n'est pas gentil pour chaque situation et C++ a toujours eu le mantra de "ne payez que pour ce que vous utilisez." Si je ne suis pas l'utilisation de plusieurs threads, ou si je suis à l'utilisation de plusieurs threads, mais je suis pas le partage de pointeur de la propriété dans les threads, atomique pointeur intelligent est exagéré. Ma deuxième question est pourquoi n'était-ce pas un non-atomique version de std::shared_ptr fournis en C++11? (en supposant qu'il existe un pourquoi) (si la réponse est tout simplement "un non-atomique version a été tout simplement jamais considéré comme" ou "personne n'a jamais demandé un non-atomique version" c'est très bien!).

À la question #2, je me demandais si quelqu'un a jamais proposé un non-atomique version de shared_ptr (soit à augmenter ou à la commission des normes) (à ne pas remplacer atomique version de shared_ptr, mais à coexister avec elle) et il a été abattu pour une raison spécifique.

126voto

Howard Hinnant Points 59526
  1. Je me demandais si il y a un non-atomique version de std::shared_ptr disponible

N'est pas fournie par la norme. Il peut être fournie par un "3ème partie" de la bibliothèque. En effet, avant C++11, et avant le coup de pouce, il semblait que tout le monde écrit leur propre référence compté pointeur intelligent (moi y compris).

  1. Ma deuxième question est pourquoi n'était-ce pas un non-atomique version de std::shared_ptr fournis en C++11?

Cette question a été discutée lors de la Rapperswil réunion en 2010. Le thème est introduit par un Organisme National, Commentaire n ° 20 de la Suisse. Il existe des arguments solides sur les deux côtés du débat, y compris celles que vous fournissez dans votre question. Toutefois, à la fin de la discussion, le vote a été massivement (mais pas à l'unanimité) à l'encontre de l'ajout d'un non synchronisé (non-atomique) version de shared_ptr.

Arguments contre inclus:

  • Le Code écrit avec la désynchronisation du shared_ptr peuvent être utilisées dans fileté code de la route, se terminant par causer difficile à déboguer des problèmes avec aucun avertissement.

  • Avoir un "universel" shared_ptr qui est le "on" à la circulation dans le comptage de référence a des avantages: à Partir de la proposition d'origine:

    A le même type d'objet, indépendamment des fonctionnalités utilisées, ce qui a grandement facilité l'interopérabilité entre les bibliothèques, y compris les bibliothèques de tiers.

  • Le coût de la atomics, tout n'est pas à zéro, n'est pas énorme. Le coût est atténué par l'utilisation de déplacer de la construction et de l'assignation de déplacement qui n'ont pas besoin d'utiliser des opérations atomiques. De telles opérations sont couramment utilisés en vector<shared_ptr<T>> d'effacer et de les insérer.

  • Rien n'interdit à des gens de l'écriture de leur propre non-atomique référence compté pointeur intelligent si c'est vraiment ce qu'ils veulent faire.

Le mot de la fin confiées au groupe de travail à Rapperswil que le jour était:

Rejeter CH 20. Pas de consensus pour faire un changement en ce moment.

62voto

Jonathan Wakely Points 45593

Howard a répondu à la question bien déjà, et Nicol fait quelques bons points sur les avantages d'avoir un seul standard de type pointeur, plutôt que beaucoup d'incompatible.

Alors que je suis complètement d'accord avec la décision du comité, je crois qu'il y a certains avantages à l'aide d'une désynchronisation shared_ptr-comme le type dans des cas particuliers, donc je l'ai étudié le sujet à quelques reprises.

Si je ne suis pas l'utilisation de plusieurs threads, ou si je suis à l'utilisation de plusieurs threads, mais je suis pas le partage de pointeur de la propriété dans les threads, atomique pointeur intelligent est exagéré.

Avec GCC lors de votre programme de ne pas utiliser plusieurs threads shared_ptr ne pas utiliser atomique ops pour le refcount. Ceci est fait par la mise à jour des compteurs de référence via un wrapper de fonctions qui permettent de détecter si le programme est multithread (sur GNU/Linux, cela se fait simplement en détectant si le programme a des liens vers d' libpthread.so) et l'expédition de atomique ou non-atomique opérations en conséquence.

J'ai réalisé il y a plusieurs années que, parce que du CCG shared_ptr<T> est mis en œuvre en termes de __shared_ptr<T, _LockPolicy> classe de base, il est possible d'utiliser la classe de base avec le single-threaded politique de verrouillage, même dans le code multithread, en utilisant explicitement __shared_ptr<T, __gnu_cxx::_S_single>. Malheureusement, parce que ce n'était pas un cas d'utilisation il ne fonctionne pas de manière optimale, et certaines opérations de toujours utiliser les fonctions wrapper et ainsi de répartition pour les opérations atomiques, même si vous avez explicitement demandé à l' _S_single politique. Voir le point (2) à http://gcc.gnu.org/ml/libstdc++/2007-10/msg00180.html pour plus de détails et un patch à GCC pour permettre à la non-atomique de mise en œuvre de l'utiliser même dans des applications multithread. J'ai été assis sur le patch depuis des années, mais j'ai finalement engagé pour GCC 4.9, ce qui vous permettra d'utiliser un alias de modèle de ce genre pour définir un pointeur partagé type qui n'est pas thread-safe, mais est légèrement plus rapide:

template<typename T>
  using shared_ptr_unsynchronized = std::shared_ptr<T, __gnu_cxx::_S_single>;

Ce type ne pourrait être interopérable avec d' std::shared_ptr<T> , et ne serait en sécurité à utiliser lorsqu'il est garanti que l' shared_ptr_unsynchronized objets ne seraient jamais être partagé entre les threads sans supplémentaires fournies par l'utilisateur synchronisation.

Si vous utilisez GCC, vous pouvez utiliser aujourd'hui par l'ajout de l' _Sp_counted_base<_S_single> explicites spécialisations de votre propre code (et de s'assurer que personne ne jamais instancie __shared_ptr<T, _S_single> sans y compris les spécialisations, pour éviter de RLL violations). L'ajout d'une telle spécialisation de l' std types est techniquement pas défini, mais pourrait fonctionner dans la pratique, parce que dans ce cas il n'y a pas de différence entre moi ajouter les spécialisations de GCC ou vous de les ajouter à votre propre code. C'est bien sûr entièrement non-portable, mais parfois, c'est OK. Avec le droit de préprocesseur hacks votre code fonctionne encore très bien avec d'autres implémentations si shared_ptr_unsynchronized<T> est un alias pour shared_ptr<T>, il serait juste un peu plus vite avec GCC.

20voto

Nicol Bolas Points 133791

Ma deuxième question est pourquoi n'était-ce pas un atomique version de std::shared_ptr fournis en C++11? (en supposant qu'il existe un pourquoi).

On pourrait tout aussi bien se demander pourquoi il n'y a pas intrusive pointeur, ou n'importe quel nombre d'autres variantes possibles de partage des pointeurs que l'on pouvait avoir.

La conception de shared_ptr, transmis de Boost, a été de créer un standard minimum lingua-franca de pointeurs intelligents. Que, généralement parlant, vous pouvez simplement tirer vers le bas le mur et l'utiliser. C'est quelque chose qui pourrait être utilisée de manière générale, à travers une grande variété d'applications. Vous pouvez le mettre dans une interface, et les chances sont de bonnes gens seront disposés à l'utiliser.

Filetage va seulement pour obtenir plus d' importance dans l'avenir. En effet, comme le temps passe, le filetage sera généralement l'un des principaux moyens d'atteindre la performance. Nécessitant la base de smart pointeur de faire le strict minimum nécessaire à l'appui de filetage facilite cette réalité.

Le Dumping d'une demi-douzaine de pointeurs intelligents avec des variations mineures entre eux dans la norme, ou pire encore, une politique basée sur pointeur intelligent, aurait été terrible. Tout le monde allait chercher le pointeur qu'ils aiment le mieux et renié tous les autres. Personne ne serait en mesure de communiquer avec quelqu'un d'autre. Ce serait comme la situation actuelle avec les chaînes C++, où tout le monde a leur propre type. Seulement, pire encore, parce que l'interaction avec des chaînes est beaucoup plus facile que l'interopération entre pointeur intelligent classes.

Coup de pouce, et, par extension, le comité a, pris un spécifique smart pointeur à utiliser. Il a fourni un bon équilibre entre les fonctions et a été largement et couramment utilisés dans la pratique.

std::vector a une certaine inefficacité par rapport à nu les tableaux dans certains cas particuliers. Il a certaines limites; certaines utilisations voulez vraiment difficile d'avoir une limite de la taille de l' vector, sans l'aide d'un lancer l'allocateur. Toutefois, le comité n'a pas de conception, vector à être tout pour tout le monde. Il a été conçu pour être une bonne valeur par défaut pour la plupart des applications. Ceux pour qui ça ne peut pas fonctionner suffit d'écrire une alternative que les suites à leurs besoins.

Comme vous pouvez le faire pour un pointeur intelligent si shared_ptr de l'atomicité est un fardeau. Là encore, on pourrait aussi envisager de ne pas les copier beaucoup.

5voto

russ Points 21

Je suis en train de préparer un exposé sur shared_ptr au travail. J'ai été en utilisant une version modifiée de boost shared_ptr à éviter de séparer la fonction malloc (comme ce que make_shared peuvent le faire) et un modèle de param pour le verrou de la politique comme shared_ptr_unsynchronized mentionnés ci-dessus. Je suis en utilisant le programme de

http://flyingfrogblog.blogspot.hk/2011/01/boosts-sharedptr-up-to-10-slower-than.html

comme un test, après le nettoyage de l'inutile shared_ptr copies. Le programme utilise le thread principal seulement, et le test argument est indiqué. Le test env est un portable fonctionnant linuxmint 14. Ici, c'est le temps de prise en secondes:

test exécutez le programme d'installation de boost(1.49) std avec make_shared modifié boost
mt-dangereux(11) 11.9 9/11.5(-pthread) 8.4 
atomique(11) de 13,6 12.4 13.0 
mt-dangereux(12) 113.5 de 85,8/108.9(-pthread) 81.5 
atomique(12) 126.0 109.1 de 123,6 

Seul le 'std' version utilise -std=cxx11, et l'-pthread probablement commutateurs lock_policy dans g++ __shared_ptr classe.

À partir de ces chiffres, je vois l'impact de la atomique instructions sur l'optimisation du code. Le cas de test n'utilise pas de C++ conteneurs, mais vecteur> est susceptible de souffrir si l'objet n'a pas besoin de la protection des fils. Boost souffre moins probablement parce que le supplément de malloc est de limiter le montant de l'in-lining et un code optimizaton.

Je n'ai pas encore trouver une machine avec assez de cœurs de test de stress de l'évolutivité de la atomique instructions, mais en utilisant std::shared_ptr uniquement lorsque cela est probablement la meilleure.

-6voto

std::shared_ptr<...> n'est pas atomique, vous devez utiliser std::atomic<std::shared_ptr<...>> pour obtenir le comportement atomique.

Notez que seuls les incrément et décrément sont atomiques par défaut alors que la copie de shared_ptr ne l’est pas.

Notez que pour changer une valeur de shared_ptr, vous devez mettre à jour deux pointeurs qui ne sont généralement pas une opération atomique.

Prograide.com

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.

Powered by:

X