c# - अस्थिर बनाम इंटरलाक्ड बनाम लॉक




multithreading locking (6)

सबसे खराब (वास्तव में काम नहीं करेगा)

public volatile के counter के एक्सेस संशोधक को बदलें

जैसा कि अन्य लोगों ने उल्लेख किया है, यह स्वयं पर वास्तव में सुरक्षित नहीं है। volatile का बिंदु यह है कि एकाधिक CPUs पर चल रहे एकाधिक थ्रेड डेटा कैश कर सकते हैं और फिर से ऑर्डर निर्देश देंगे।

यदि यह volatile नहीं है , और सीपीयू ए एक मान बढ़ाता है, तो CPU बी वास्तव में कुछ समय बाद उस वृद्धिशील मान को नहीं देख सकता है, जो समस्याएं पैदा कर सकता है।

यदि यह volatile , तो यह सुनिश्चित करता है कि दो CPU एक ही समय में एक ही डेटा देखें। यह उन्हें अपने पढ़ने और लिखने के संचालन को अंतःस्थापित करने से रोकता नहीं है, जो समस्या है जिसे आप टालने की कोशिश कर रहे हैं।

दूसरा सबसे अच्छा:

lock(this.locker) this.counter++ ;

यह करना सुरक्षित है (बशर्ते आपको हर जगह lock करना याद रखें कि आप इस. this.counter तक this.counter )। यह किसी अन्य थ्रेड को locker द्वारा संरक्षित किसी भी अन्य कोड को निष्पादित करने से रोकता है। ताले का उपयोग करना, उपरोक्त के रूप में बहु-सीपीयू रीडरिंग समस्याओं को रोकता है, जो कि बढ़िया है।

समस्या यह है कि, लॉकिंग धीमी है, और यदि आप locker को किसी अन्य स्थान पर दोबारा उपयोग करते हैं जो वास्तव में संबंधित नहीं है तो आप किसी भी कारण से अपने अन्य धागे को अवरुद्ध कर सकते हैं।

श्रेष्ठ

Interlocked.Increment(ref this.counter);

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

मैं पूरी तरह से यकीन नहीं कर रहा हूं, हालांकि अगर यह अन्य सीपीयू चीजों को फिर से व्यवस्थित करता है, या यदि आपको वृद्धि के साथ अस्थिरता को जोड़ना भी आवश्यक है।

InterlockedNotes:

  1. अनियंत्रित तरीके कोर या सीपीयू की किसी भी संख्या पर निश्चित रूप से सुरक्षित हैं।
  2. इंटरलाक्ड विधियां उनके द्वारा निष्पादित निर्देशों के चारों ओर एक पूर्ण बाड़ लागू करती हैं, इसलिए पुनरावृत्ति नहीं होती है।
  3. इंटरलाक्ड विधियों को अस्थिर क्षेत्र तक पहुंच का समर्थन करने की आवश्यकता नहीं है या यहां तक कि अस्थिरता को दिए गए क्षेत्र पर संचालन के आसपास आधा बाड़ नहीं है और इंटरलाक्ड पूर्ण बाड़ का उपयोग कर रहा है।

फुटनोट: वास्तव में क्या अस्थिर है।

चूंकि volatile इस तरह के बहुप्रचार मुद्दों को नहीं रोकता है, इसके लिए क्या है? एक अच्छा उदाहरण यह है कि आपके पास दो धागे हैं, जो हमेशा एक चर (लिखते हैं queueLength ) लिखते हैं, और वह जो हमेशा उसी चर से पढ़ता है।

यदि queueLength अस्थिर नहीं है, तो थ्रेड ए पांच बार लिख सकता है, लेकिन थ्रेड बी उन लोगों को देख सकता है क्योंकि देरी हो रही है (या यहां तक ​​कि गलत क्रम में भी)।

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

आइए मान लें कि एक वर्ग में एक public int counter फ़ील्ड है जिसे एकाधिक धागे से एक्सेस किया जाता है। यह int केवल वृद्धि या कमी है।

इस क्षेत्र को बढ़ाने के लिए, किस दृष्टिकोण का उपयोग किया जाना चाहिए, और क्यों?

  • lock(this.locker) this.counter++; ,
  • Interlocked.Increment(ref this.counter); ,
  • public volatile के counter के एक्सेस संशोधक को बदलें।

अब जब मैंने volatile खोज की है, तो मैं कई lock स्टेटमेंट और Interlocked के उपयोग को हटा रहा हूं। लेकिन क्या ऐसा करने का कोई कारण नहीं है?


" volatile " Interlocked.Increment जगह नहीं है! यह सिर्फ यह सुनिश्चित करता है कि परिवर्तनीय कैश नहीं किया गया है, लेकिन सीधे उपयोग किया जाता है।

एक चर को बढ़ाने के लिए वास्तव में तीन ऑपरेशन की आवश्यकता होती है:

  1. पढ़ना
  2. वेतन वृद्धि
  3. लिखना

Interlocked.Increment एक ही परमाणु ऑपरेशन के रूप में सभी तीन भागों प्रदर्शन करता है।


मैं जॉन स्कीट का दूसरा जवाब देता हूं और उन सभी के लिए निम्नलिखित लिंक जोड़ना चाहता हूं जो "अस्थिर" और इंटरलाक्ड के बारे में अधिक जानना चाहते हैं:

परमाणुता, अस्थिरता और अपरिवर्तनीयता अलग-अलग हैं, भाग एक - (कोडिंग में एरिक लिपर्ट का शानदार एडवेंचर्स)

परमाणुता, अस्थिरता और अपरिवर्तनीयता अलग-अलग हैं, भाग दो

परमाणुता, अस्थिरता और अपरिवर्तनीयता अलग-अलग हैं, भाग तीन

सियोनारा वाष्पशील - (2012 में दिखाई देने वाले जो डफी के वेबलॉग की वेबैक मशीन स्नैपशॉट)


मैंने यह देखने के लिए कुछ परीक्षण किया कि सिद्धांत वास्तव में कैसे काम करता है: kennethxu.blogspot.com/2009/05/interlocked-vs-monitor-performance.html । मेरा परीक्षण तुलनाएक्सकेनेज पर अधिक केंद्रित था लेकिन वृद्धि के लिए परिणाम समान है। मल्टी-सीपीयू पर्यावरण में इंटरलाक्ड आवश्यक नहीं है। यहां 2 साल के 16 सीपीयू सर्वर पर वृद्धि के लिए परीक्षा परिणाम दिया गया है। ध्यान रखें कि परीक्षण में बढ़ोतरी के बाद भी सुरक्षित पढ़ना शामिल है, जो वास्तविक दुनिया में विशिष्ट है।

D:\>InterlockVsMonitor.exe 16
Using 16 threads:
          InterlockAtomic.RunIncrement         (ns):   8355 Average,   8302 Minimal,   8409 Maxmial
    MonitorVolatileAtomic.RunIncrement         (ns):   7077 Average,   6843 Minimal,   7243 Maxmial

D:\>InterlockVsMonitor.exe 4
Using 4 threads:
          InterlockAtomic.RunIncrement         (ns):   4319 Average,   4319 Minimal,   4321 Maxmial
    MonitorVolatileAtomic.RunIncrement         (ns):    933 Average,    802 Minimal,   1018 Maxmial

लॉक (...) काम करता है, लेकिन थ्रेड को अवरुद्ध कर सकता है, और अगर अन्य कोड एक ही असंगत तरीके से एक ही ताले का उपयोग कर रहा है तो डेडलॉक का कारण बन सकता है।

इंटरलाक्ड। * यह करने का सही तरीका है ... आधुनिक सीपीयू के रूप में बहुत कम ओवरहेड इसे आदिम के रूप में समर्थन देता है।

अपने आप पर अस्थिर सही नहीं है। एक थ्रेड पुनर्प्राप्त करने का प्रयास कर रहा है और फिर एक संशोधित मान वापस लिखना अभी भी एक और थ्रेड के साथ संघर्ष कर सकता है।


सी # संदर्भ में थ्रेडिंग पढ़ें। इसमें आपके प्रश्न के इन्स और आउट शामिल हैं। तीनों में से प्रत्येक के अलग-अलग उद्देश्यों और दुष्प्रभाव होते हैं।





interlocked