2015-01-01 15 views
16

क्लैंग के थ्रेड सैनिटाइज़र के साथ काम करते समय हमने डेटा रेस चेतावनियां देखीं। हमें लगता है कि यह std :: स्ट्रिंग की कॉपी-ऑन-राइट तकनीक के कारण थ्रेड सुरक्षित नहीं है, लेकिन हम गलत हो सकते हैं। जब धागे से संकलित प्रक्षालक सक्षमएक बहु थ्रेडेड वातावरण में std :: स्ट्रिंग का उपयोग करते समय क्लैंग का थ्रेड सैनिटाइज़र चेतावनी

void test3() { 
    std::unique_ptr<std::thread> thread; 

    { 
    auto output = make_shared<string>(); 
    std::string str = "test"; 
    thread.reset(new std::thread([str, output]() { *output += str; })); 
    // The str string now goes out of scope but due to COW 
    // the captured string may not have the copy of the content yet. 
    } 

    thread->join(); 
} 

:: हम चेतावनी हम इस कोड को देख रहे थे कम

clang++ -stdlib=libc++ -std=c++11 -O0 -g -fsanitize=thread -lpthread -o test main.cpp 

या

clang++ -std=c++11 -O0 -g -fsanitize=thread -lpthread -o test main.cpp 

और जब एक से अधिक बार चलाने के लिए, यह अंततः इस का उत्पादन चेतावनी:

WARNING: ThreadSanitizer: data race (pid=30829) 
    Write of size 8 at 0x7d0c0000bef8 by thread T62: 
    #0 operator delete(void*) <null>:0 
    ... 

    Previous write of size 1 at 0x7d0c0000befd by thread T5: 
    #0 std::__1::char_traits<char>::assign(char&, char const&) string:639 
    ... 

क्या यह थ्रेड सैनिटाइज़र से झूठा सकारात्मक है या क्या यह वास्तविक डेटा रेस है? यदि बाद में, कोड को बदलने के बिना इसे चारों ओर काम किया जा सकता है (उदाहरण के लिए कंपाइलर को कुछ झंडे पास करके), क्या यह स्ट्रिंग इम्प्लेमेंटेशन (या कुछ और) में एक बग है?

अद्यतन: बजना --version आउटपुट:

Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5) 
Target: x86_64-pc-linux-gnu 
Thread model: posix 

अद्यतन: The cpp मैं इस चेतावनी पुन: पेश करने का उपयोग करें।

+4

libC++ गाय तारों का उपयोग नहीं करना चाहिए, इसलिए मुझे आश्चर्य होगा अगर गाय स्ट्रिंग इसका कारण हैं। – hvd

+0

@ बार्टोज़्ज़केपी, हां, क्षमा करें, यह एक गाय समस्या है, परीक्षण अनुमान में तर्क से समर्थित हमारे अनुमान थे। अनिवार्य रूप से हमें कोड थ्रेड को सुरक्षित करने की आवश्यकता है, समस्या यह है कि कभी-कभी हमें अंदर से इसी तरह की चेतावनियां मिलती हैं उदा। boost :: asio ताकि हम कोड को बदलने की स्थिति में हमेशा न हों। –

+0

क्लैंग का थ्रेड सैनिटाइज़र एक अच्छा उपकरण है, लेकिन सभी तरह के म्यूटेक्स और अन्य सिंक्रनाइज़ेशन तकनीकों को सही ढंग से समझना बहुत मुश्किल है। यहां मामला हो सकता है - मुझे इससे कुछ झूठे अलार्म मिल गए हैं, उदाहरण के लिए, यह क्यूटी के म्यूटेक्स को समझ में नहीं आता है। – BartoszKP

उत्तर

2

[संपादित करें] नीचे दी गई धारणा दोषपूर्ण साबित होती है, टिप्पणियों में लिंक देखें। टी 5, टी 62 नहीं उपरोक्त कोड में धागा है।

थ्रेड आईडी को समझना उपयोगी होगा, लेकिन मुझे लगता है कि टी 5 मुख्य धागा है और टी 62 स्पॉन्टेड थ्रेड है। ऐसा लगता है कि कॉपी मुख्य धागे पर बनाई गई है (नए थ्रेड से पहले) और नए धागे (स्पष्ट रूप से) पर नष्ट हो गया। यह सुरक्षित है क्योंकि नया धागा मौजूद होने से पहले मुख्य धागे के साथ दौड़ नहीं सकता है।

इसलिए, यह एक धागा sanitizer बग है। यह जांचने में असफल रहा कि पिछले लिखने के समय थ्रेड टी 62 अस्तित्व में था या नहीं।

+0

हां, थ्रेड टी 5 वह प्रतीत होता है जिसने test3 फ़ंक्शन और T62 को लम्बा को निष्पादित किया है। [यहां पूर्ण टीएसएन चेतावनी है] (https://gist.github.com/inetic/b73a8a0f4186c8fe034d#file-thread_sanitizer_warning-output)। तो ऐसा लगता है कि आप सही हैं, अगर आपको कोई फर्क नहीं पड़ता है तो मैं जवाब को चिह्नित करने से पहले थोड़ा और अधिक समय दूंगा। –

+0

यह चेतावनी अपेक्षाकृत जटिल है। उस पूर्ण संदर्भ के साथ, यह स्पष्ट है कि न तो टी 5 और न ही टी 62 मुख्य धागा (!) है, ऐसा लगता है कि आपके पास 'test2() 'था जो एक ही स्मृति का उपयोग करने के लिए हुआ था। – MSalters

+0

[यहां] (https://gist.github.com/inetic/b73a8a0f4186c8fe034d#file-thread_sanitizer_warning-cpp) चेतावनी उत्पन्न करने के लिए प्रयुक्त सीपीपी कोड है (लाइन संख्या मेल नहीं खाएगी, क्षमा करें)। आप सही हैं कि न तो टी 5 और न ही टी 62 मुख्य धागा है, मैं चेतावनी को पुन: उत्पन्न करने के लिए कई अलग-अलग धागे में test3 फ़ंक्शन चलाता हूं। हालांकि, प्रत्येक test3 आमंत्रण के बीच कोई साझा स्मृति नहीं है, इसलिए मुझे विश्वास नहीं है कि इसमें बहुत अंतर है (?)। –

1

यह काफी मुश्किल है। मैं नीचे अपने कोड में तर्क सारांश तैयार किया है:

(20.8.2.2:

  
    In thread T62: 
     Create string s (with reference count) 
     Create output_1 pointing to s in the thread storage for T62 
     Create thread T5 
     Create output_2 pointing to s in the thread storage for T5 
    Sync point 
    In thread T5: 
     Append to s ** MODIFY ** 
     Thread-safe decrement of reference count for s (not a sync point) 
     End of output_2 lifetime 
     Exit 
    In thread T62: 
     Thread-safe decrement of reference count for s (not a sync point) 
     End of output_1 lifetime 
     Deallocate s ** MODIFY ** 
     Join 
    Sync point 
    In thread T62: 
     Destroy T5 

जहां तक ​​मेरा बता सकते हैं, मानक shared_ptr Deleter बुला के संबंध में सिंक्रनाइज़ेशन के बारे में कोई गारंटी नहीं देता/4) डेटा रेस की उपस्थिति को निर्धारित करने के प्रयोजनों के लिए, सदस्य फ़ंक्शंस केवल shared_ptr और weak_ptr ऑब्जेक्ट्स को एक्सेस और संशोधित करेंगे, न कि ऑब्जेक्ट्स जिन्हें वे संदर्भित करते हैं।

मैं इसका मतलब यह है कि किसी भी संशोधन है कि वास्तव में करने के लिए उठाई-इस तरह के किसी भी संशोधन Deleter बना सकता है के रूप में shared_ptr के एक सदस्य समारोह, बुला जबकि वस्तु, माना जाता है होता है के दायरे से बाहर होने के लिए ले shared_ptr, और इसलिए यह सुनिश्चित करने के लिए कि वे डेटा रेस नहीं पेश करते हैं, shared_ptr की ज़िम्मेदारी नहीं है। उदाहरण के लिए, T5 द्वारा स्ट्रिंग में किए गए संशोधनों को T62 तक दिखाई नहीं दे सकता है, जब तक टी 62 इसे नष्ट करने का प्रयास करता है।

हालांकि, हर्ब Sutter, उसकी "परमाणु <> हथियारों" बात में संकेत दिया है कि वह एक बग दोनों अधिग्रहण बिना shared_ptr नाशक में संदर्भ गिनती के परमाणु घटती है और रिलीज शब्दों के रूप में देखा है, लेकिन मैं कर रहा हूँ सुनिश्चित नहीं है कि यह मानक का उल्लंघन कैसे करता है।

+0

मैं यहां कुछ हद तक नुकसान पहुंचा रहा हूं। क्या वह धागा 'थ्रेड-> जुड़ने के बाद नहीं चला जाता है() '? IOW, क्या अभी भी दौड़ने के लिए दौड़ने वाला धागा है? – MSalters

+0

@MSalters: जरूरी नहीं। जुड़ने से पहले धागा समाप्त हो सकता है। जब तक यह पहले से बाहर नहीं निकला है तो थ्रेड केवल निकलता है जब तक शामिल हो जाता है। –

+0

ठीक है, अब मुझे मिल गया। यह आपके परिदृश्य को बताता है। मैं सहमत हूं, यह शायद सही स्पष्टीकरण है। – MSalters

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