Lorsque je transition mon code sur C ++ 11, j'aimerais beaucoup convertir mon code Pthread en STD :: Thread. Cependant, je semble avoir de fausses conditions de race sur des programmes très simples en DRD et dans Helgrind. Snippet de sortie Helgrind - Je reçois aussi des erreurs similaires dans DRD, à l'aide de GCC 4.6.1, Valgrind 3.7.0 sur Ubuntu 11.11 AMD64. P> Mes questions sont les suivantes: p> Je suis réticent à porter une tonne de code de Pthread à
std :: thread code> jusqu'à ce que certains outils cruciaux tels que Helgrind / DRD ont rattrapé. P>
==19347== ---Thread-Announcement------------------------------------------
==19347==
==19347== Thread #1 is the program's root thread
==19347==
==19347== ---Thread-Announcement------------------------------------------
==19347==
==19347== Thread #2 was created
==19347== at 0x564C85E: clone (clone.S:77)
==19347== by 0x4E37E7F: do_clone.constprop.3 (createthread.c:75)
==19347== by 0x4E39604: pthread_create@@GLIBC_2.2.5 (createthread.c:256)
==19347== by 0x4C2B3DA: pthread_create_WRK (hg_intercepts.c:255)
==19347== by 0x4C2B55E: pthread_create@* (hg_intercepts.c:286)
==19347== by 0x50BED02: std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==19347== by 0x400D51: _ZNSt6threadC1IZ4mainEUlvE_IEEEOT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400C60: main (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347==
==19347== ----------------------------------------------------------------
==19347==
==19347== Possible data race during write of size 8 at 0x5B8E060 by thread #1
==19347== Locks held: none
==19347== at 0x40165E: _ZNSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEED1Ev (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401895: _ZNKSt19_Sp_destroy_inplaceINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEEEclEPS6_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x4016D8: _ZNSt19_Sp_counted_deleterIPNSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEESt19_Sp_destroy_inplaceIS6_ESaIS6_ELN9__gnu_cxx12_Lock_policyE2EE10_M_disposeEv (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401B83: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401B3E: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401A93: std::__shared_ptr<std::thread::_Impl_base, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401AAD: std::shared_ptr<std::thread::_Impl_base>::~shared_ptr() (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400D5D: _ZNSt6threadC1IZ4mainEUlvE_IEEEOT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400C60: main (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347==
==19347== This conflicts with a previous read of size 8 by thread #2
==19347== Locks held: none
==19347== at 0x50BEABE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==19347== by 0x4C2B547: mythread_wrapper (hg_intercepts.c:219)
==19347== by 0x4E38EFB: start_thread (pthread_create.c:304)
==19347== by 0x564C89C: clone (clone.S:112)
==19347==
==19347== Address 0x5B8E060 is 32 bytes inside a block of size 64 alloc'd
==19347== at 0x4C29059: operator new(unsigned long) (vg_replace_malloc.c:287)
==19347== by 0x4012E9: _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEESaIS8_ELNS_12_Lock_policyE2EEE8allocateEmPKv (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x40117C: _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE2EEC1INSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEESaISA_EIS9_EEESt19_Sp_make_shared_tagPT_RKT0_DpOT1_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x4010B9: _ZNSt12__shared_ptrINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEELN9__gnu_cxx12_Lock_policyE2EEC1ISaIS6_EIS5_EEESt19_Sp_make_shared_tagRKT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401063: _ZNSt10shared_ptrINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEEEC1ISaIS6_EIS5_EEESt19_Sp_make_shared_tagRKT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401009: _ZSt15allocate_sharedINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEESaIS6_EIS5_EESt10shared_ptrIT_ERKT0_DpOT1_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400EF7: _ZSt11make_sharedINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEEIS5_EESt10shared_ptrIT_EDpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400E17: _ZNSt6thread15_M_make_routineISt12_Bind_resultIvFZ4mainEUlvE_vEEEESt10shared_ptrINS_5_ImplIT_EEEOS7_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400D2B: _ZNSt6threadC1IZ4mainEUlvE_IEEEOT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400C60: main (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347==
==19347== ----------------------------------------------------------------
==19347==
3 Réponses :
Très probablement Ce que vous voyez sont de faux positifs. J'obtilise un comportement similaire dans mon code. P>
Plus précisément, les avertissements semblent liés à la mise en œuvre de la classe de pointeur partagée, et ma compréhension est que sur votre plate-forme (que je présume X86 / x86-64?) GCC utilise une instruction d'assemblage atomique optimisée dans la référence du pointeur partagé. Compter les machines. Le problème est que Valgrind est capable de détecter des erreurs lors de l'utilisation des primitives de POSIX (verrous, mutexes, ETx.), Mais il n'est pas capable de faire face aux primitives de niveau inférieur. P>
Ce que j'ai fait jusqu'à présent consiste simplement à filtrer à partir de la sortie de Valgrind les avertissements (éventuellement que vous puissiez écrire un fichier de suppression qui fait le travail de manière appropriée). P>
THX pour le chèque de santé mentale - j'ai sauté dans la conversion de Pthreads en STD :: Thread. À l'exception de SCOPING STD :: conditionnelle_variable correctement, la majeure partie du portage était indolore (pas surprenante, puisque Pthreads n'est pas si loin en dessous). Je ferai fermer des erreurs de drd / hélicoptères avec des suppressions au cours des deux ou deux et les ajoutent à l'OP.
std :: thread utilise un pointeur partagé en interne. Ce que vous voyez sont de faux positifs sur le nombre de références de cet objet pointeur partagé. Vous pouvez éviter ces faux positifs en ajoutant les quatre lignes de code présentées ci-dessous dans chaque fichier source juste avant que l'en-tête C ++ inclue les directives. Remarque: cela ne fonctionne que avec la version de LibstDC ++ incluse avec GCC 4.6.0 ou version ultérieure.
#include <valgrind/drd.h> #define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(addr) ANNOTATE_HAPPENS_BEFORE(addr) #define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(addr) ANNOTATE_HAPPENS_AFTER(addr) #define _GLIBCXX_EXTERN_TEMPLATE -1
Remarque: vient de découvrir qu'il existe un bug dans libstdc ++ qui ne permet pas correctement à STD :: thread d'être annoté correctement - voir aussi Bug de GCC 51504 .
Si vous utilisez Boost, vous pouvez activer l'utilisation des primitives Pthreads au lieu d'opérations atomiques pour les pointeurs partagés. Vous pouvez ensuite utiliser une version de votre code compilée avec boost_sp_use_pthreads pour l'analyse de Helgrind et vous n'obtiendrez pas les erreurs car Helgrind comprend les primitives Pthreads. P>
voir http://www.boost.org /doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm#hreadsafety Pour plus d'informations. P>