2010-03-26 8 views
6

Dans le boost::shared_ptr destructor, cela se fait:Pourquoi le compteur de référence de boost :: shared_ptr n'est-il pas volatile?

if(--*pn == 0) 
{ 
    boost::checked_delete(px); 
    delete pn; 
} 

pn est un pointeur sur le compteur de référence, qui est typedefed comme

shared_ptr::count_type -> detail::atomic_count -> long 

Je me serais attendu à la long être volatile long, étant donné l'utilisation de threads et le 0-check-and-deletion non-atomique dans le destructeur shared_ptr ci-dessus. Pourquoi n'est-ce pas volatile?

EDIT:

Il se trouve que je regardais l'en-tête utilisé lorsque l'utilisation multi-thread n'est pas spécifiée (atomic_count.hpp). Dans atomic_count_win32.hpp, la diminution est correctement implémentée pour une utilisation multithread.

+0

Où avez-vous trouvé ce code btw? – jalf

+0

@jalf: shared_ptr_nmt.hpp –

Répondre

16

Parce que volatile n'est pas nécessaire pour le multithreading, et n'a rien de bénéfique, mais potentiellement détruit un certain nombre d'optimisations. Afin d'assurer un accès multithread sécurisé à une variable, la primitive dont nous avons besoin est une barrière de mémoire, qui fournit à la fois la garantie volatile et quelques autres (elle empêche le réordonnancement de l'accès à la mémoire à travers la barrière, qui n'est pas volatile fais)

Je crois que shared_ptr utilise des opérations atomiques lorsque cela est possible, ce qui fournit implicitement une barrière de mémoire. Sinon, il revient à un mutex, qui fournit également une barrière de mémoire.

Voir Why is volatile not considered useful in multithreaded C or C++ programming? ou http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/ pour plus de détails

Modifier
count_type est pas un long dans le cas général. C'est convertible à un long. Si vous regardez dans atomic_count.hpp, le typedef à long n'est appliqué que si aucun thread n'est disponible (dans ce cas, aucune synchronisation n'est nécessaire). Sinon, il utilise l'implémentation définie dans boost/smart_ptr/detail/atomic_count_pthreads.hpp ou boost/smart_ptr/detail/atomic_count_win32.hpp ou l'un des autres fichiers répertoriés. Et ce sont des classes wrapper synchronisées qui assurent que toutes les opérations sont effectuées de manière atomique.

+0

"Je crois que shared_ptr utilise des opérations atomiques si possible" - pas dans mon exemple cité avec le destructeur, où se trouve mon problème maintenant ... –

+0

Eh bien, faire de la variable 'volatile' n'aurait rien changé. Vous avez raison, décrémenter et comparer un long contre zéro semble dangereux, mais cela dépend de ce que fait le * reste * de la classe pointeur. – jalf

+0

@jalf: Eh bien, c'est toi qui m'as perdu.;-) En ce moment, dans mon exemple, deux threads entrent dans shared_ptrdtor et "le reste de la classe de pointeur" ne fait rien d'autre. –

8

volatile n'a pratiquement rien à voir avec le filetage. Voir here.

+0

Diriez-vous qu'il n'y a pas de problème avec le traitement ci-dessus du compteur dans le destructeur, s'il est exécuté sur différents threads? –

2

Vous interprétez mal le code. atomic_count est défini simplement comme un long si le code n'utilise pas le multithreading:

#ifndef BOOST_HAS_THREADS 

namespace boost 
{ 

namespace detail 
{ 

typedef long atomic_count; 

} 

} 

#elif //... include various platform-specific headers that define atomic_count class 

#endif 
+0

Merci! Editer la question pour clarifier les choses. (Avait déjà accepté la réponse de Jalf) –