2013-08-02 7 views
6

सी या सी ++ प्रोग्राम में, यदि 2 थ्रेड एक ही वैश्विक चर का उपयोग करते हैं, तो आपको var को mutex के माध्यम से लॉक करने की आवश्यकता है।किस मामले में मुझे एक चर से एक चर को लॉक करने की आवश्यकता है?

लेकिन किस मामले में वास्तव में?

  1. थ्रेड 1: धागा 2 पढ़ें: पढ़ा
  2. थ्रेड 1: धागा 2 लिखें: लिखने थ्रेड 2:: लिखने
बेशक

आप मामले में लॉक करने की आवश्यकता

  • थ्रेड 1 पढ़ 3 लेकिन अन्य 2 मामलों के साथ क्या है? मामले 2 (गैर परमाणु संचालन के साथ) पर क्या होता है? क्या किसी प्रकार का एक्सेस उल्लंघन है या थ्रेड 2 को पुराना मान मिलता है? मैं इसके बारे में उलझन में हूं, क्योंकि हार्डवेयर स्तर पर स्मृति और रजिस्ट्रारों को एक ही समय में (सामान्य पीसी हार्डवेयर में) एक्सेस नहीं किया जा सकता है या क्या हमारे पास समांतर बस लाइनों के साथ समांतर बस लाइनों के साथ समानांतर सीपीयू हैं?

  • +11

    मामले 2 और 3, यानी कोई भी स्थिति जिसमें कम से कम एक धागा कम से कम एक अन्य थ्रेड पढ़ने या लिखने के साथ लिख रहा है। – juanchopanza

    +0

    आपको विभिन्न धागे से डेटा तक पहुंचने पर हमेशा लॉक करने की आवश्यकता नहीं है। परमाणु परिचालनों को देखें, और विशेष रूप से सी ++ 11 के 'std :: atomic' – nijansen

    +0

    पर और हां, अपने अंतिम वाक्य को संबोधित करने के लिए, मल्टीकोर सीपीयू पर कैश के विभिन्न स्तरों में प्रत्येक मान की कई प्रतियां हो सकती हैं। – Hulk

    उत्तर

    8

    बस सोचें कि प्रत्येक मामले में क्या हो सकता है। आइए केवल दौड़ की स्थिति पर विचार करें: यह आसान है और परिणाम देखने के लिए हमारे लिए पर्याप्त है।

    मामले 1 में, चर संशोधित किया गया है नहीं किया जा रहा है, तो कोई बात नहीं जो आदेश है, दोनों धागे एक ही मूल्य पढ़ा जाएगा। तो मूल रूप से, यहां कुछ भी गलत नहीं है।

    मामले 2 और 3 खराब हैं। मान लीजिए कि आप एक रेस स्थिति है, और पता नहीं है जो धागे के पहले पहुंच मिल जाएगी करते हैं। इसका मतलब है:

    मामले 2 के लिए: सभी परिचालनों के अंत में चर का मान ठीक है (यह थ्रेड 1 द्वारा लिखा गया मान होगा), लेकिन थ्रेड 2 को चर का पुराना मान मिल सकता है, जो हो सकता है एक दुर्घटना, या अन्य समस्याओं का कारण बनता है।

    मामले 3 के लिए: चर के अंत के बाद से यह मूल्य पर जो धागा लिखने आपरेशन पिछले प्रदर्शन करेंगे निर्भर करता है, उम्मीद के मुताबिक नहीं है।

    मामलों 2 और 3 के लिए, यह भी हो सकता है कि थ्रेड्स में से एक एक परिवर्तनीय स्थिति में चर का उपयोग करने का प्रयास करेगा, और आप धागे में से किसी एक द्वारा पढ़े गए कुछ कचरे वाले डेटा के साथ समाप्त हो सकते हैं (यानी केस 2), या सभी परिचालनों को पूरा करने के बाद चर में डेटा भी कचरा।

    तो हां, मामलों 2 के लिए ताला और 3.

    +3

    केस 2 काफी खराब हो सकता है: परिवर्तक थ्रेड द्वारा पढ़े जाने पर एक असंगत स्थिति में हो सकता है। – juanchopanza

    +0

    @juanchopanza, हाँ यह सच है (मामले 3 के लिए भी), लेकिन मैंने इसका उल्लेख नहीं किया कि जवाब को अधिक जटिल न करें । क्या मुझे इसे उत्तर में जोड़ना चाहिए, या इसे छोड़ देना चाहिए? – SingerOfTheFall

    +4

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

    3

    लॉकिंग के लिए नियमों को सरल कर रहे हैं:

    आप एक चर, समवर्ती एक और धागा द्वारा पहुँचा करने के लिए लिखते हैं, तो आप के समुचित अनुक्रमण की जरूरत है संचालन (उदाहरण के लिए, लॉकिंग के माध्यम से)। कोई लिखने, तुल्यकालन

  • लिखें, समवर्ती उपयोग करने के लिए कोई ज़रूरत नहीं, समवर्ती पहुँच

    1. , तुल्यकालन की जरूरत
    2. लिखें:

  • इस सरल नियम के साथ

    , हम आसानी से मामलों में से प्रत्येक का मूल्यांकन कर सकते , सिंक्रनाइज़ेशन

    और यदि आप लॉक नहीं करते हैं तो क्या होगा?

    अच्छा, औपचारिक रूप से, यह अपरिभाषित व्यवहार है। मतलब है कि हम नहीं जानते हैं। हालांकि, जबकि एकमात्र संभावित प्रतिक्रिया इस मुद्दे की सीमा को समझने में मदद करती है।

    • पढ़ने के मामले में: पढ़ने के मामले में एक बासी मूल्य
    • के लिए उपयोग: एक आंशिक मूल्य के लिए उपयोग (केवल आधा पर अद्यतन किया जाता है

      मशीन स्तर पर, क्या हो सकता है या तो है समय तुम देखो)

    • लिखने के मामले में: मान

    ... और चलो भूल नहीं की अंतिम मूल्य एक गोलमाल (बिट के स्तर पर है) कि जब भी आप कोई गलत सूचक/आकार पढ़ यह एक सीआर का कारण बन सकता है राख।

    कंपाइलर स्तर पर, संकलक को अनुकूलित कर सकता है जैसे कि धागे का एकमात्र उपयोग था। इस मामले में यह भी हो सकता है:

    • को हटाने "अनावश्यक" पढ़ता है: if (flag) while (true) में while (flag) बदलने ...
    • को हटाने "अप्रयुक्त" लिखते हैं
    • ...

    स्मृति की उपस्थिति बाड़ और स्पष्ट सिंक्रनाइज़ेशन निर्देश (जो म्यूटेक्स का उपयोग शुरू करते हैं) उन अनुकूलन को रोकते हैं।

    2

    नियम सरल है: अगर एक वस्तु (पढ़ना या लिखना) पहुँचा जा सकता है एक से अधिक थ्रेड के, और किसी भी धागा द्वारा, सभी संशोधित किया गया है तो सिंक्रनाइज़ करने की आवश्यकता एक्सेस करता है। अन्यथा, आपने व्यवहार को अपरिभाषित किया है।

    0

    यह काफी के रूप में सरल नहीं के रूप में यह दो मामलों को छोड़कर, लग सकता है है: सिंक्रनाइज़ करने के लिए, कभी जरूरत नहीं

    1. जब केवल पाठकों और कोई लेखकों देखते हैं, तो आप करते हैं।
    2. जब कई धागे लिखते हैं और उनमें से कम से कम एक पढ़ना-संशोधित-लेखन ऑपरेशन (जैसे ++x;) कर रहा है तो आप हमेशा सिंक्रनाइज़ करने की आवश्यकता है, या आपको पूरी तरह से अप्रत्याशित परिणाम मिलेंगे।

    अन्य सभी मामलों में, यदि आप कम से कम एक लेखक और एक पाठक (या कई लेखकों) है, तो आप आमतौर पर (बहुत कुछ अपवादों को छोड़कर) का उपयोग सिंक्रनाइज़ करने के लिए की जरूरत है, लेकिन जरूरी नहीं कि हमेशा की तरह, और हमेशा सख्त संभव तरीके से नहीं।

    यह बहुत अधिक निर्भर करता है कि आपको किस गारंटी की आवश्यकता है। कुछ अनुप्रयोगों को धागे पर सख्त अनुक्रमिक स्थिरता की आवश्यकता होती है (और कभी-कभी आपको लॉक निष्पक्षता की भी आवश्यकता होती है)। कुछ अनुप्रयोग समान रूप से अच्छी तरह से काम करेंगे, लेकिन बहुत बेहतर प्रदर्शन के साथ, यदि वे केवल एक ही थ्रेड के भीतर गारंटी से पहले होते हैं। फिर भी अन्य अनुप्रयोगों को भी इतना जरूरत नहीं है और वे आराम से संचालन या पूरी तरह से गारंटी के बिना पूरी तरह से खुश हैं।

    // worker thread 
    running = true; 
    while(running) { task = pull_task(); execute(task); } 
    
    // main thread exit code 
    running = false; 
    join(workerthread); 
    

    यह किसी भी तुल्यकालन के बिना पूरी तरह से अच्छी तरह से काम करता है:

    उदाहरण के लिए, इस "विशिष्ट" एक कार्यकर्ता धागा के कार्यान्वयन एक लेखक और एक पाठक है। हां, पैडेंटिकली बोलना यह अनिर्धारित है कि running का मूल्य कब बदल जाएगा, लेकिन वास्तव में इससे कोई फर्क नहीं पड़ता। स्मृति स्थान में कुछ "यादृच्छिक" मध्यवर्ती मूल्य नहीं हो सकता है, और इससे कोई फर्क नहीं पड़ता कि परिवर्तन पहले या बाद में कुछ दर्जन नैनोसेकंड दिखाई देता है क्योंकि कार्यकर्ता धागा किसी भी कार्य को निष्पादित करने में व्यस्त होगा, और सबसे बुरे मामले में यह कुछ मिलीसेकंड बाद में परिवर्तन को उठाता है। आखिरकार, अगले पुनरावृत्ति पर, कार्यकर्ता धागा परिवर्तन उठाएगा और बाहर निकल जाएगा।
    कुछ साल पहले डॉ। डॉबब में प्रकाशित एसपीएससी फास्ट-फॉरवर्ड कतार एक समान सिद्धांत पर काम करती थी, केवल पॉइंटर्स के साथ।

    कई अलग सिंक्रनाइज़ेशन मोडों पर उनके अच्छे और व्यापक पढ़ने और उनके प्रभाव GCC documentation में दिए गए हैं।

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