J'utilise Valgrind --Tool = DRD pour vérifier mon application qui utilise Boost :: thread. Fondamentalement, l'application remplit un ensemble de valeurs "livre" avec des valeurs "KeHai" basées sur des entrées via une connexion à socket.
sur un thread séparé, un utilisateur peut se connecter et obtenir les livres leur envoyer. P> Son assez simple, donc j'ai pensé à utiliser un boost :: mutex :: scoped_lock sur l'emplacement qui sertialise le livre et l'emplacement qui efface les données du livre devrait suffire à éviter toute condition de course. Voici le code: P>
==26330== Conflicting store by thread 1 at 0x0658fbb0 size 4 ==26330== at 0x653AE68: std::string::_M_mutate(unsigned int, unsigned int, unsigned int) (in /usr/lib/libstdc++.so.6.0.8) ==26330== by 0x653AFC9: std::string::_M_replace_safe(unsigned int, unsigned int, char const*, unsigned int) (in /usr/lib/libstdc++.so.6.0.8) ==26330== by 0x653B064: std::string::assign(char const*, unsigned int) (in /usr/lib/libstdc++.so.6.0.8) ==26330== by 0x653B134: std::string::assign(char const*) (in /usr/lib/libstdc++.so.6.0.8) ==26330== by 0x8055D64: Book::Kehai::clear() (Book.h:50) ==26330== by 0x8094A29: Book::clear() (Book.cpp:78) ==26330== by 0x808537E: RealKernel::start() (RealKernel.cpp:86) ==26330== by 0x804D15A: main (main.cpp:164) ==26330== Allocation context: BSS section of /usr/lib/libstdc++.so.6.0.8 ==26330== Other segment start (thread 2) ==26330== at 0x400BB59: pthread_mutex_unlock (drd_pthread_intercepts.c:633) ==26330== by 0xC59565: pthread_mutex_unlock (in /lib/libc-2.5.so) ==26330== by 0x805477C: boost::mutex::unlock() (mutex.hpp:56) ==26330== by 0x80547C9: boost::unique_lock<boost::mutex>::~unique_lock() (locks.hpp:340) ==26330== by 0x80949BA: Book::copyChangedKehaiToString(char*) const (Book.cpp:134) ==26330== by 0x80937EE: BookSerializer::serializeBook(Book const&, std::string const&) (BookSerializer.cpp:41) ==26330== by 0x8092D05: BookSnapshotManager::getSnaphotDataList() (BookSnapshotManager.cpp:72) ==26330== by 0x8088179: SnapshotServer::getDataList() (SnapshotServer.cpp:246) ==26330== by 0x808870F: SnapshotServer::run() (SnapshotServer.cpp:183) ==26330== by 0x808BAF5: boost::_mfi::mf0<void, RealThread>::operator()(RealThread*) const (mem_fn_template.hpp:49) ==26330== by 0x808BB4D: void boost::_bi::list1<boost::_bi::value<RealThread*> >::operator()<boost::_mfi::mf0<void, RealThread>, boost::_bi::list0>(boost::_bi::type<void>, boost::_mfi::mf0<void, RealThread>&, boost::_bi::list0&, int) (bind.hpp:253) ==26330== by 0x808BB90: boost::_bi::bind_t<void, boost::_mfi::mf0<void, RealThread>, boost::_bi::list1<boost::_bi::value<RealThread*> > >::operator()() (bind_template.hpp:20) ==26330== Other segment end (thread 2) ==26330== at 0x400B62A: pthread_mutex_lock (drd_pthread_intercepts.c:580) ==26330== by 0xC59535: pthread_mutex_lock (in /lib/libc-2.5.so) ==26330== by 0x80546B8: boost::mutex::lock() (mutex.hpp:51) ==26330== by 0x805473B: boost::unique_lock<boost::mutex>::lock() (locks.hpp:349) ==26330== by 0x8054769: boost::unique_lock<boost::mutex>::unique_lock(boost::mutex&) (locks.hpp:227) ==26330== by 0x8094711: Book::copyChangedKehaiToString(char*) const (Book.cpp:113) ==26330== by 0x80937EE: BookSerializer::serializeBook(Book const&, std::string const&) (BookSerializer.cpp:41) ==26330== by 0x808870F: SnapshotServer::run() (SnapshotServer.cpp:183) ==26330== by 0x808BAF5: boost::_mfi::mf0<void, RealThread>::operator()(RealThread*) const (mem_fn_template.hpp:49) ==26330== by 0x808BB4D: void boost::_bi::list1<boost::_bi::value<RealThread*> >::operator()<boost::_mfi::mf0<void, RealThread>, boost::_bi::list0>(boost::_bi::type<void>, boost::_mfi::mf0<void, RealThread>&, boost::_bi::list0&, int) (bind.hpp:253)
4 Réponses :
Nevermind. Je suis un idiot et j'ai réussi à oublier que les chaînes C ++ sont mutables. J'ai changé le code pour utiliser des chaînes de style C et mes problèmes de condition de course sont partis. P>
Sur un de côté pour que quiconque lisait ce post, quelqu'un connaît-il une bonne bibliothèque de chaînes immuables pour C ++? Je pensais que Boost en avait un, mais je n'ai pas été en mesure de trouver quelque chose de concluant. p>
Merci. P>
J'ai travaillé avec des filets et des cordes STD :: Strings (ou des conteneurs STL ..) Sans aucun problème si tout est correctement protégé. Quel compilateur / stl utilisez-vous?
c'est un problème connu avec C ++ STL STL. Comme ils utilisent le comptage de référence et sont mutables, ce problème semble être habitué régulièrement. Utilisation de GCC 4.1 sur Centos 5
Selon mon commentaire sur une autre réponse, vous pouvez forcer la STL à copier plutôt que clone [string2 = string1.c_str ()]. Vous pouvez même créer une classe "porte-chaîne de fil de fil" qui encapsule ce travail autour et est utilisé dans tous les objets partagés qui stockent des chaînes - alors il est plus difficile d'oublier de le faire correctement et de modifier la mise en œuvre si vous passez à une STL non-bouchée.
Après votre message, j'ai pris le temps de vous en apprendre davantage sur Valgrind et comment sa sortie devrait être lue.
Je peux voir ce qui suit: p>
vous invoquez Entre-temps, l'autre thread a accédé à la même position de mémoire, d'où cette situation est considéré comme une condition de race. p> examine maintenant le "contexte" de l'autre thread. Valgrind ne montre pas son emplacement exact de la pile, mais il apparaît entre lesquels "segments" il s'est produit. Selon Valgrind, un segment est un bloc consécutif d'accès à la mémoire délimitée par des opérations de synchronisation. P> Nous voyons que ce bloc Maintenant, regardez les informations de localisation de la mémoire conflictuelle: P> Book :: Effacer Code> Quelles appels à tour de rôle
Book :: kehai :: Effacer code>, où vous attribuez une valeur à une chaîne. À l'intérieur du
std :: string :: Attribuer code> La STL fait quelque chose qui stocke une certaine valeur à l'adresse 0x0658fbb0. P>
pthread_mutex_unlock code> et et
pthread_mutex_lock code>.
Moyens - Le même emplacement de mémoire a été accédé lorsque votre mutex n'a pas été verrouillé et que le fil était quelque part en dehors de vos deux fonctions. P>
Allocation context: BSS section of /usr/lib/libstdc++.so.6.0.8
Valdo, merci pour la mise à jour. Oui, je pense que c'est le même problème exact. Quand j'ai tout changé de cordes de style C, les erreurs sont parties.
C'est un poste utile néanmoins. Maintenant, je pense tester mes applications avec Valgrind, j'utilise fortement le filetage. À propos des chaînes: vous dites que le problème disparaît lorsque vous passez à "Cordes de style C". Mais qu'est-ce que vous appelez les "chaînes de style c"? Plus précisément - quelle est votre politique sur leur manipulation et leur vie. Je crois que le problème est lié au fait que vos chaînes sont comptées ou non. Des moyens - lorsque vous attribuez une chaîne à une autre: créez-vous une copie de votre chaîne ou vous allouez un autre identique à cela? Et si c'est compté - est-ce le fil-faire?
STL est censé être du thread-coffre-fort en ce sens que ce n'est pas un problème de les utiliser avec du fil si vous vous verrez correctement ou si vous effectuez simplement des lectures multi-threads.
STL est censé être du thread-coffre-fort en ce sens que ce n'est pas un problème de les utiliser avec du fil si vous vous verrouillez correctement ou si vous effectuez simplement des lectures multi-threads p>
Surprise! Oui, c'est supposé em>, mais laissez-moi vous dire un magasin sur ce que est arrivé em>. P>
J'ai eu une application multimètre-hreade. Il y avait une source de données avec des chaînes (
std :: string code>). Il a été verrouillé avec une section critique. P>
D'autres objets ont finalement besoin de prendre des cordes à partir de là. Ils ont fait une copie de ces chaînes de la manière suivante: p>
xxx pré> la même stratégie a été utilisée pour ajuster ces chaînes: p>
xxx pré> < p> et, devinez quoi? Crashes! P> Mais pourquoi? Étant donné que la déclaration d'affectation de la chaîne ne produit pas vraiment une copie du bloc de mémoire qui détient la chaîne. Au lieu de cela, le même bloc de mémoire est réutilisé (référencé). P>
Eh bien, ce n'est pas nécessairement mauvais. Mais la mauvaise chose était que STD :: String a mis en œuvre le comptage de référence des cordes non sous une manière thread-sûre. Il a utilisé des arithmétiques réguliers ++ et - au lieu de
interlockedincrement code> et etc. P>
Qu'est-il arrivé est que le
STR code> fait référence à la même chaîne. Et puis, il finit par le désirer dans son destructeur (ou lorsqu'il est explicitement attribué à une autre chaîne). Et cela arrive extérieur fort> de la région verrouillée. P>
de sorte que ces chaînes ne soient pas utilisées dans une application multi-threadée. Et il est presque impossible de mettre en œuvre un verrouillage correct pour fonctionner dans ce domaine, car les données référencées réellement passent silencieusement de l'objet à l'objet à un objet. P>
et que strong> La mise en œuvre de STL a été déclarée de sécurité. p> blockQuote>
Vous pouvez probablement forcer la copie à copier, par exemple. g_sometr = str.c_str ()? [Évidemment un travail horrible, et mieux pour passer à une STL non-bouchée.]
Oui, il y a toujours une mauvaise mise en œuvre, mais ce n'est pas toujours le cas
Ce rapport peut être ignoré en toute sécurité. Il est déclenché par comment STD :: String est implémentée dans LIBSTDC ++. Ce problème a été résolu dans la version LibstDC ++ incluse avec GCC 4.4.4 ou ultérieur. Voir aussi Objet de GCC BugZilla # 40518 pour les détails. P >