2011-12-06 17 views
11

के लिए drd और helgrind समर्थन की वर्तमान स्थिति के रूप में जब मैं अपना कोड C++ 11 में बदलता हूं, तो मैं अपने pthread कोड को std :: thread में परिवर्तित करना चाहता हूं। हालांकि, मुझे ड्रड और हेल्ग्रिंड में बहुत ही सरल कार्यक्रमों पर झूठी दौड़ की स्थिति मिल रही है।std :: thread

#include <thread> 

int main(int argc, char** argv) 
{ 
    std::thread t([]() { }); 
    t.join(); 
    return 0; 
} 

Helgrind उत्पादन टुकड़ा - मैं भी उबंटू 11.11 amd64 पर जीसीसी 4.6.1, valgrind 3.7.0 का उपयोग कर, DRD में इसी तरह की त्रुटियों को मिलता है।

मेरे प्रश्न हैं:

  • मानसिक स्वास्थ्य की जांच: मैंने कुछ गलत कर रहा हूँ? क्या दूसरों को सरल std :: थ्रेड प्रोग्राम पर समान झूठी रिपोर्ट मिल रही हैं?
  • दौड़-परिस्थितियों का पता लगाने के लिए std :: thread के वर्तमान उपयोगकर्ता क्या हैं?

मैं पैथ्रेड से std::thread तक कोड के टन को बंद करने के लिए अनिच्छुक हूं, जब तक कि कुछ महत्वपूर्ण उपकरण जैसे हेल्ग्रिंड/ड्रड पकड़े गए हों।

==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: [email protected]@GLIBC_2.2.5 (createthread.c:256) 
==19347== by 0x4C2B3DA: pthread_create_WRK (hg_intercepts.c:255) 
==19347== by 0x4C2B55E: [email protected]* (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== 

उत्तर

12

std :: thread आंतरिक रूप से साझा पॉइंटर का उपयोग करता है। जो आप देख रहे हैं वह उस साझा पॉइंटर ऑब्जेक्ट की संदर्भ संख्या पर झूठी सकारात्मक हैं। सी ++ हेडर में निर्देशों को शामिल करने से ठीक पहले आप प्रत्येक स्रोत फ़ाइल में नीचे दिखाए गए कोड की चार पंक्तियों को जोड़कर इन झूठी सकारात्मकताओं से बच सकते हैं। नोट: यह केवल libccdC++ के संस्करण के साथ काम करता है जिसमें जीसीसी 4.6.0 या बाद में शामिल है।

#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 

अधिक जानकारी के लिए भी libstdc में डाटा रेस शिकार अनुभाग ++ पुस्तिका (http://gcc.gnu.org/onlinedocs/libstdc++/manual/debug.html) देखें।

+0

+1 शानदार टिप! मैं निश्चित रूप से इसे कोशिश करूँगा - thx। – kfmfe04

+2

नोट: अभी पता चला है कि libstdC++ में एक बग है जो std :: thread को ठीक से एनोटेट करने की अनुमति नहीं देता है - यह भी देखें [gcc bug 51504] (http://gcc.gnu.org/bugzilla/show_bug.cgi ? id = 51,504)। – user251384

3

जो भी आप देख रहे हैं वह झूठी सकारात्मक हैं। मैं अपने कोड में एक समान व्यवहार देख रहा हूं।

विशेष रूप से, चेतावनियां साझा सूचक वर्ग के कार्यान्वयन से संबंधित प्रतीत होती हैं, और मेरी समझ यह है कि आपके प्लेटफॉर्म पर (जिसे मैं मानता हूं x86/x86-64 है?) जीसीसी साझा पॉइंटर में अनुकूलित परमाणु असेंबली निर्देश का उपयोग कर रहा है संदर्भ गिनती मशीनरी। समस्या यह है कि पॉज़िक्स प्राइमेटिव्स (ताले, म्यूटेक्स, ईटीएक्स।) का उपयोग करते समय वालग्रिंड त्रुटियों का पता लगाने में सक्षम है, लेकिन यह निम्न स्तर के प्राइमेटिव से निपटने में सक्षम नहीं है।

मैं अब तक क्या किया है बस के उत्पादन valgrind चेतावनी से को फ़िल्टर करना है (संभवतः आपको लगता है कि उचित तरीके से काम करता है कुछ दमन फ़ाइल लिख सकता है)।

+0

सैनिटी चेक के लिए thx - मैं pthreads को std :: thread में परिवर्तित करने में कूद गया। std :: conditional_variable देखते हुए सही ढंग के अपवाद के साथ, पोर्टिंग के सबसे (, आश्चर्य की बात नहीं नहीं अब तक नीचे में pthreads के बाद से) दर्द रहित था। मैं अगले दिन या दो में दमन के साथ कुछ drd/helgrind त्रुटियों को लोहे से निकाल दूंगा और उन्हें ओपी में जोड़ दूंगा। – kfmfe04

1

यदि आप बूस्ट का उपयोग करते हैं तो आप साझा पॉइंटर्स के लिए परमाणु संचालन के बजाय pthreads primitives के उपयोग को चालू कर सकते हैं। फिर आप हेल्ग्रिंड विश्लेषण के लिए BOOST_SP_USE_PTHREADS के साथ संकलित आपके कोड के एक संस्करण का उपयोग कर सकते हैं, और आपको त्रुटियां नहीं मिलेंगी क्योंकि हेल्ग्रिंड pthreads primitives को समझता है।

अधिक जानकारी के लिए http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety देखें।

संबंधित मुद्दे