.NET में डबल चेकिंग लॉकिंग में वाष्पशील संशोधक की आवश्यकता


85

एकाधिक ग्रंथों का कहना है कि .NET में डबल-चेक लॉकिंग को लागू करते समय आप जिस फ़ील्ड पर लॉक कर रहे हैं, उसमें वाष्पशील संशोधक लागू होना चाहिए। लेकिन वास्तव में क्यों? निम्नलिखित उदाहरण को ध्यान में रखते हुए:

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }
   }
}

"आवश्यक मेमोरी संगति" को "लॉक (सिंकरूट)" क्यों नहीं करता है? क्या यह सच नहीं है कि "लॉक" कथन के बाद, पढ़ना और लिखना दोनों अस्थिर होगा और इसलिए आवश्यक स्थिरता पूरी हो जाएगी?


2
यह पहले से ही कई बार चबाया गया है। yoda.arachsys.com/csharp/singleton.html
हंस

1
दुर्भाग्य से उस लेख में जॉन ने दो बार 'अस्थिर' संदर्भ दिया, और न ही संदर्भ सीधे उन कोड उदाहरणों को संदर्भित करता है जो उन्होंने दिए थे।
दान एस्पेरज़ा

चिंता को समझने के लिए यह लेख देखें: igoro.com/archive/volatile-keyword-in-c-memory-model-explained मूल रूप से यह JOR के लिए उदाहरण चर के लिए सीपीयू रजिस्टर का उपयोग करना संभव है - विशेषकर यदि आपको आवश्यकता हो वहाँ थोड़ा अतिरिक्त कोड। इस प्रकार यदि एक बयान में दो बार संभावित रूप से एक ही मान लौटाया जा सकता है, भले ही वह किसी अन्य थ्रेड पर बदल रहा हो। वास्तव में इसका उत्तर थोड़ा जटिल है कि लॉक स्टेटमेंट यहां चीजों को बेहतर बनाने के लिए जिम्मेदार हो सकता है या नहीं भी हो सकता है (जारी)
user2685937

(पिछली टिप्पणी देखें जारी रखें) - यहाँ पर मुझे लगता है कि वास्तव में ऐसा हो रहा है - मूल रूप से कोई भी कोड जो पढ़ने या सेट करने से अधिक जटिल होता है, कहने के लिए JIT को ट्रिगर कर सकता है, इसे अनुकूलित करने की कोशिश करना भूल जाओ बस लोड करें और मेमोरी में सहेजें क्योंकि यदि किसी फ़ंक्शन को JIT कहा जाता है, तो संभावित रूप से रजिस्टर को सहेजने और फिर से लोड करने की आवश्यकता होगी यदि वह इसे हर बार संग्रहीत करता है, बजाय इसके कि यह बस हर बार मेमोरी से सीधे लिखता है और पढ़ता है। मुझे कैसे पता चलेगा कि ताला कुछ खास नहीं है? मैं इगोर से पिछली टिप्पणी में पोस्ट किए गए लिंक को
देखता हूं

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

जवाबों:


59

अस्थिर अनावश्यक है। अच्छी तरह की**

volatileचर पर पढ़ता है और लिखता है के बीच एक स्मृति बाधा बनाने के लिए प्रयोग किया जाता है।
lock, जब उपयोग किया जाता है, तो ब्लॉक के चारों ओर lockएक थ्रेड तक पहुंच को सीमित करने के अलावा, मेमोरी अवरोधों का कारण बनता है ।
मेमोरी बैरियर इसे बनाते हैं इसलिए प्रत्येक थ्रेड वेरिएबल का सबसे करंट वैल्यू (किसी रजिस्टर में कैश्ड लोकल वैल्यू नहीं) पढ़ता है और यह कंपाइलर स्टेटमेंट को रीऑर्डर नहीं करता है। उपयोग करना volatileअनावश्यक है ** क्योंकि आपको पहले से ही एक ताला मिला है।

जोसेफ अलबहारी ने इस सामान को पहले से बेहतर बताया।

और सी # में सिंगलटन को लागू करने के लिए जॉन स्कीट के मार्गदर्शिका की जांच करना सुनिश्चित करें


अद्यतन :
* volatileचर को पढ़ता है VolatileReadऔर एस होने के लिए लिखता है VolatileWrite, जो x86 और x64 पर सीएलआर पर लिखता है , एक पर लागू होता है MemoryBarrier। वे अन्य प्रणालियों पर बारीक हो सकते हैं।

** मेरा उत्तर केवल सही है यदि आप x86 और x64 प्रोसेसर पर सीएलआर का उपयोग कर रहे हैं। यह अन्य मेमोरी मॉडल में सच हो सकता है, जैसे मोनो (और अन्य कार्यान्वयन), इटेनियम 64 और भविष्य के हार्डवेयर। यह वही है जो जॉन ने डबल चेकिंग लॉकिंग के लिए "गोचैस" में अपने लेख में उल्लेख किया है।

{{चर को चिन्हित करना volatile, उसे पढ़ना Thread.VolatileReadया कॉल को सम्मिलित करना Thread.MemoryBarrier} में से एक करना कोड के कमजोर मेमोरी मॉडल की स्थिति में ठीक से काम करने के लिए आवश्यक हो सकता है।

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

मैंने इन लेखों को भी उपयोगी पाया है:
http://www.codeproject.com/KB/tips/MemoryBarrier.aspx
vance morrison का लेख (इसके बारे में सब कुछ लिंक, यह डबल चेक किए गए लॉकिंग के बारे में बात करता है)
chris brumme का लेख (इसके बारे में सब कुछ लिंक) )
जो डफी: डबल चेक्ड लॉकिंग के टूटे हुए वेरिएंट

मल्टीस्ट्रेडिंग पर luis abreu की श्रृंखला अवधारणाओं का एक अच्छा अवलोकन भी देती है
http://msmvps.com/blogs/luisabreu/archive/2009/06/29/multithreading-load-and-store-reordering.aspx
http: // msmvps। कॉम / ब्लॉग / luisabreu / संग्रह / 2009/07/03 / multithreading-शुरू-स्मृति-fences.aspx


जॉन स्कीट वास्तव में कहते हैं कि उचित मेमोरी बारियर बनाने के लिए वाष्पशील संशोधक की आवश्यकता होती है, जबकि पहले लिंक लेखक का कहना है कि लॉक (मॉनिटर.इंटर) पर्याप्त होगा। वास्तव में सही कौन है ???
कोन्स्टेंटिन

@Konstantin ऐसा लगता है कि जॉन इटेनियम 64 प्रोसेसर पर मेमोरी मॉडल का उल्लेख कर रहे थे, इसलिए उस स्थिति में, वाष्पशील का उपयोग करना आवश्यक हो सकता है। हालाँकि, x86 और x64 प्रोसेसर पर अस्थिरता अनावश्यक है। मैं थोड़ा और अपडेट करूंगा।
डेन

यदि लॉक वास्तव में एक मेमोरी बैरियर बना रहा है और यदि मेमोरी बारियर वास्तव में इंस्ट्रक्शन ऑर्डर और कैश अमान्य दोनों के बारे में है, तो उसे सभी प्रोसेसर पर काम करना चाहिए। वैसे भी यह बहुत अजीब है कि इस तरह की बुनियादी चीज बहुत भ्रम का कारण बनती है ...
कॉन्स्टेंटिन

2
यह उत्तर मुझे गलत लगता है। यदि किसी भी मंच volatileपर अनावश्यक था तो इसका मतलब होगा कि JIT उस प्लेटफ़ॉर्म पर मेमोरी भार का अनुकूलन नहीं कर सकता है। यह मेरे लिए बहुत संभावना नहीं है। object s1 = syncRoot; object s2 = syncRoot;object s1 = syncRoot; object s2 = s1;
user541686

1
यहां तक ​​कि अगर CLR लिखता नहीं है (मुझे संदेह है कि यह सच है, ऐसा करने से कई बहुत अच्छे अनुकूलन किए जा सकते हैं), यह तब भी बगिया होगा जब तक हम कंस्ट्रक्टर कॉल को इनलाइन कर सकते हैं और ऑब्जेक्ट को इन-प्लेस बना सकते हैं (हम एक आधा आरंभिक वस्तु देख सकते हैं)। किसी भी मेमोरी मॉडल का स्वतंत्र अंतर्निहित सीपीयू उपयोग करता है! एरिक लिपर्ट के अनुसार इंटेल पर सीएलआर कम से कम कंस्ट्रक्टर्स के बाद एक संस्मरण का परिचय देता है जो उस अनुकूलन को नकारता है, लेकिन यह कल्पना द्वारा आवश्यक नहीं है और मैं उदाहरण के लिए एआरएम पर होने वाली एक ही चीज़ पर भरोसा नहीं करूंगा ..
वू

34

volatileक्षेत्र के बिना इसे लागू करने का एक तरीका है । मैं इसे समझाता हूँ ...

मुझे लगता है कि यह लॉक के अंदर मेमोरी एक्सेस रीऑर्डरिंग है जो खतरनाक है, जैसे कि आप लॉक के बाहर एक पूरी तरह से प्रारंभिक उदाहरण नहीं प्राप्त कर सकते हैं। इससे बचने के लिए मैं ऐसा करता हूं:

public sealed class Singleton
{
   private static Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         // very fast test, without implicit memory barriers or locks
         if (instance == null)
         {
            lock (syncRoot)
            {
               if (instance == null)
               {
                    var temp = new Singleton();

                    // ensures that the instance is well initialized,
                    // and only then, it assigns the static variable.
                    System.Threading.Thread.MemoryBarrier();
                    instance = temp;
               }
            }
         }

         return instance;
      }
   }
}

कोड को समझना

कल्पना कीजिए कि सिंग्लटन वर्ग के निर्माता के अंदर कुछ आरंभीकरण कोड हैं। यदि फ़ील्ड के नए ऑब्जेक्ट के पते के साथ सेट होने के बाद ये निर्देश पुन: व्यवस्थित किए जाते हैं, तो आपके पास एक अधूरा उदाहरण है ... कल्पना करें कि कक्षा में यह कोड है:

private int _value;
public int Value { get { return this._value; } }

private Singleton()
{
    this._value = 1;
}

अब नए ऑपरेटर का उपयोग करके निर्माता को कॉल की कल्पना करें:

instance = new Singleton();

इसे इन परिचालनों में विस्तारित किया जा सकता है:

ptr = allocate memory for Singleton;
set ptr._value to 1;
set Singleton.instance to ptr;

क्या होगा अगर मैं इन निर्देशों को इस तरह से पुन: व्यवस्थित करता हूं:

ptr = allocate memory for Singleton;
set Singleton.instance to ptr;
set ptr._value to 1;

क्या इससे कोई फर्क पड़ता है? कोई आप एक ही धागे के बारे में सोच सकते हैं। यस यदि आप कई थ्रेड्स के बारे में सोचते हैं ... क्या होगा यदि थ्रेड को बस के बाद बाधित किया जाता है set instance to ptr:

ptr = allocate memory for Singleton;
set Singleton.instance to ptr;
-- thread interruped here, this can happen inside a lock --
set ptr._value to 1; -- Singleton.instance is not completelly initialized

यह है कि स्मृति बाधा से बचता है, स्मृति अभिगमन को अनुमति नहीं देकर:

ptr = allocate memory for Singleton;
set temp to ptr; // temp is a local variable (that is important)
set ptr._value to 1;
-- memory barrier... cannot reorder writes after this point, or reads before it --
-- Singleton.instance is still null --
set Singleton.instance to temp;

हैप्पी कोडिंग!


1
यदि CLR आरंभिक होने से पहले किसी ऑब्जेक्ट तक पहुंच की अनुमति देता है, तो यह एक सुरक्षा छेद है। एक ऐसे विशेषाधिकार प्राप्त वर्ग की कल्पना करें जिसका एकमात्र सार्वजनिक निर्माणकर्ता "SecureMode = 1" सेट करता है और फिर जिसकी आवृत्ति विधियाँ जाँचती हैं। यदि आप बिना कंस्ट्रक्टर के उन इंस्टेंस विधियों को चला सकते हैं, तो आप सुरक्षा मॉडल को तोड़ सकते हैं और सैंडबॉक्सिंग का उल्लंघन कर सकते हैं।
माइकलजी

1
@MichaelGG: आपके द्वारा वर्णित मामले में, यदि वह वर्ग इसे एक्सेस करने के लिए कई थ्रेड्स का समर्थन करेगा, तो यह एक समस्या है। यदि कंस्ट्रक्टर कॉल को जिटर द्वारा इनबिल्ट किया जाता है, तो सीपीयू के लिए निर्देशों को इस तरह से पुन: व्यवस्थित करना संभव है कि संग्रहीत संदर्भ बिंदु पूरी तरह से प्रारंभिक उदाहरण पर नहीं। यह एक सीएलआर सुरक्षा समस्या नहीं है क्योंकि यह परिहार्य है, यह प्रोग्रामर का उपयोग करने की जिम्मेदारी है: ऐसे वर्ग के निर्माता के अंदर इंटरलॉक, मेमोरी बैरियर, ताले और / या अस्थिर क्षेत्र।
मिगुएल एंजेलो

2
Ctor के अंदर एक अवरोध इसे ठीक नहीं करता है। यदि CLR ने नई आवंटित वस्तु के संदर्भ को ctor के पूर्ण होने से पहले और एक संस्मरण को सम्मिलित नहीं किया है, तो एक और सूत्र सेमी-इनिशियलाइज्ड ऑब्जेक्ट पर एक इंस्टेंस विधि निष्पादित कर सकता है।
माइकलजी

यह "वैकल्पिक पैटर्न" है जिसे ReSharper 2016/2017 C # में DCL के मामले में सुझाता है। OTOH, जावा करता है गारंटी नहीं है कि का परिणाम newपूरी तरह से आरंभ ..
user2864740

मुझे पता है कि एमएस .नेट कार्यान्वयन बाधा के अंत में एक मेमोरी अवरोध रखता है ... लेकिन इसका बेहतर सॉरी से सुरक्षित होना चाहिए।
मिगुएल एंजेलो

7

मुझे नहीं लगता कि किसी ने वास्तव में सवाल का जवाब दिया है , इसलिए मैं इसे आज़माऊंगा।

अस्थिर और पहले if (instance == null)"आवश्यक" नहीं हैं। लॉक इस कोड को थ्रेड-सुरक्षित बना देगा।

तो सवाल यह है: आप पहले क्यों जोड़ेंगे if (instance == null)?

कारण संभवतः कोड के बंद खंड को अनावश्यक रूप से निष्पादित करने से बचना है। जब आप लॉक के अंदर कोड निष्पादित कर रहे होते हैं, तो कोई भी अन्य धागा जो उस कोड को निष्पादित करने की कोशिश करता है, वह ब्लॉक हो जाता है, जो कई थ्रेड्स से अक्सर सिंगलटन को एक्सेस करने का प्रयास करने पर आपके प्रोग्राम को धीमा कर देगा। भाषा / मंच के आधार पर, लॉक से ओवरहेड्स भी हो सकते हैं जिनसे आप बचना चाहते हैं।

तो पहले अशक्त जांच को वास्तव में त्वरित तरीके से जोड़ा जाता है ताकि आपको लॉक की आवश्यकता हो। यदि आपको सिंगलटन बनाने की आवश्यकता नहीं है, तो आप लॉक से पूरी तरह से बच सकते हैं।

लेकिन आप यह नहीं देख सकते हैं कि यह संदर्भ किसी तरह से लॉक किए बिना अशक्त है, क्योंकि प्रोसेसर कैशिंग के कारण, एक और धागा इसे बदल सकता है और आप एक "बासी" मूल्य पढ़ेंगे जो आपको अनावश्यक रूप से लॉक दर्ज करने के लिए प्रेरित करेगा। लेकिन आप एक लॉक से बचने की कोशिश कर रहे हैं!

इसलिए आप यह सुनिश्चित करने के लिए सिंगलटन को अस्थिर करते हैं कि आप नवीनतम मूल्य को पढ़ते हैं, बिना लॉक का उपयोग किए बिना।

आपको अभी भी आंतरिक लॉक की आवश्यकता है क्योंकि अस्थिर केवल चर तक पहुंच के दौरान आपकी रक्षा करता है - आप लॉक का उपयोग किए बिना इसे सुरक्षित रूप से परीक्षण और सेट नहीं कर सकते।

अब, क्या यह वास्तव में उपयोगी है?

वैसे मैं कहूंगा "ज्यादातर मामलों में, नहीं"।

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

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

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


6
यह कहीं न कहीं गलत है और बात याद आ रही है। volatileडबल-चेक लॉकिंग में लॉक शब्दार्थ के साथ कुछ नहीं करना है, यह मेमोरी मॉडल और कैश सुसंगतता के साथ करना है। इसका उद्देश्य यह सुनिश्चित करना है कि एक थ्रेड को एक मान प्राप्त नहीं होता है जिसे अभी भी दूसरे थ्रेड द्वारा प्रारंभ किया जा रहा है, जिसे डबल-चेक लॉक पैटर्न स्वाभाविक रूप से नहीं रोकता है। जावा में आपको निश्चित रूप से volatileकीवर्ड की आवश्यकता है ; .नेट में यह गलत है, क्योंकि यह ECMA के अनुसार गलत है लेकिन रनटाइम के अनुसार सही है। किसी भी तरह, lockनिश्चित रूप से इसका ध्यान नहीं रखता है।
हारून

है ना? मैं नहीं देख सकता कि आपका कथन मेरे कहे अनुसार असहमत है, और न ही मैंने कहा है कि वाष्पशील किसी भी तरह से लॉक शब्दार्थ से संबंधित है।
जेसन विलियम्स

6
इस धागे में कई अन्य कथनों की तरह आपका उत्तर, दावा करता है कि lockकोड थ्रेड को सुरक्षित बनाता है। यह हिस्सा सही है, लेकिन डबल-चेक लॉक पैटर्न इसे असुरक्षित बना सकता है । जो आपको याद आ रहा है। यह उत्तर थ्रेड सुरक्षा मुद्दों को संबोधित किए बिना डबल-चेक लॉक के अर्थ और उद्देश्य के बारे में पता लगाने के लिए लगता है जो इसका कारण हैं volatile
Aaronaught

1
यदि instanceइसे चिह्नित किया जाता है तो यह असुरक्षित कैसे बना सकता है volatile?
यूजरकंट्रोल

5

आपको डबल चेक लॉक पैटर्न के साथ अस्थिर का उपयोग करना चाहिए।

अधिकांश लोग इस लेख को प्रमाण के रूप में इंगित करते हैं, जिसमें आपको अस्थिरता की आवश्यकता नहीं है: https://msdn.microsoft.com/en-us/magazine/cc163715.aspx#S10

लेकिन वे अंत तक पढ़ने में विफल रहते हैं: " चेतावनी का एक अंतिम शब्द - मैं केवल मौजूदा प्रोसेसर पर देखे गए व्यवहार से x86 मेमोरी मॉडल का अनुमान लगा रहा हूं। इस प्रकार कम-लॉक तकनीक भी नाजुक हैं क्योंकि हार्डवेयर और कंपाइलर समय के साथ अधिक आक्रामक हो सकते हैं। यहाँ अपने कोड पर इस नाजुकता के प्रभाव को कम करने के लिए कुछ रणनीतियाँ दी गई हैं। पहले, जब भी संभव हो, लो-लॉक तकनीकों से बचें (...) अंत में, निहित स्मृति पर भरोसा करने के बजाय अस्थिर घोषणाओं का उपयोग करते हुए, सबसे कमजोर मेमोरी मॉडल को संभव मानें। । "

यदि आपको अधिक समझाने की आवश्यकता है तो ECMA युक्ति पर इस लेख को अन्य प्लेटफार्मों के लिए उपयोग किया जाएगा: msdn.microsoft.com/en-us/magazine/jj863136.aspx

यदि आपको इस नए लेख को पढ़ने के लिए और अधिक आश्वस्त करने की आवश्यकता है, जिसमें अनुकूलन किए जा सकते हैं, तो इसे बिना किसी अस्थिरता के काम करने से रोकें: msdn.microsoft.com/en-us/magazine/jj883956.aspx

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


1
अच्छा उत्तर। इस प्रश्न पर एकमात्र सही उत्तर सरल "नहीं" है। इसके अनुसार स्वीकृत उत्तर गलत है।
डेनिस कसेल

3

AFAIK (और - इसे सावधानी से लें, मैं बहुत समवर्ती सामान नहीं कर रहा हूं) नहीं। ताला सिर्फ आपको कई दावेदारों (थ्रेड्स) के बीच सिंक्रनाइज़ेशन देता है।

दूसरी ओर अस्थिर आपकी मशीन को हर बार मूल्य का पुनर्मूल्यांकन करने के लिए कहता है, ताकि आप एक कैशेड (और गलत) मूल्य पर ठोकर न खाएं।

Http://msdn.microsoft.com/en-us/library/ms998558.aspx देखें और निम्नलिखित उद्धरण पर ध्यान दें:

साथ ही, चर को अस्थिर करने के लिए घोषित किया जाता है ताकि यह सुनिश्चित किया जा सके कि उदाहरण चर तक पहुँच से पहले आवृत्ति चर पूरा हो जाए।

वाष्पशील का विवरण: http://msdn.microsoft.com/en-us/library/x13ttww7%28VS.71%29.aspx


2
एक 'लॉक' एक वाष्प अवरोधक भी प्रदान करता है, जो कि (या इससे बेहतर) अस्थिर है।
हेन्क होल्टरमैन

2

मुझे लगता है कि मुझे वह मिल गया है जिसकी मुझे तलाश थी। विवरण इस लेख में हैं - http://msdn.microsoft.com/en-us/magazine/cc163715.aspx#S10

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


1
उस लेख के बहुत नीचे ध्यान से पढ़ें, विशेष रूप से अंतिम वाक्य में लेखक ने कहा है: "ए फाइनल वर्ड ऑफ़ वार्निंग - मैं केवल मौजूदा प्रोसेसर पर देखे गए व्यवहार से x86 मेमोरी मॉडल का अनुमान लगा रहा हूं। इस प्रकार कम-लॉक तकनीक भी नाजुक हैं। हार्डवेयर और कंपाइलर समय के साथ और अधिक आक्रामक हो सकते हैं। आपके कोड पर इस नाजुकता के प्रभाव को कम करने के लिए कुछ रणनीतियाँ हैं। पहले, जब भी संभव हो, लो-लॉक तकनीकों से बचें। (...) अंत में, सबसे कमजोर मेमोरी मॉडल को संभव मानें। निहित गारंटी पर भरोसा करने के बजाय अस्थिर घोषणाओं का उपयोग करना। "
user2685937 18

1
यदि आपको और अधिक आश्वस्त करने की आवश्यकता है, तो ईसीएमए युक्ति पर इस लेख को अन्य प्लेटफार्मों के लिए उपयोग किया जाएगा: msdn.microsoft.com/en-us/magazine/jj863136.aspx इसे बिना किसी अस्थिरता के काम करने से रोकें: msdn.microsoft.com/en-us/magazine/jj883956.aspx सारांश में यह "आपके लिए" क्षण के लिए अस्थिरता के बिना काम कर सकता है, लेकिन इसे उचित कोड लिखने का मौका न दें और इसका उपयोग करें वाष्पशील या वोलेटाइलीड / लिखने के तरीके।
user2685937

1

lockपर्याप्त है। एमएस भाषा युक्ति (3.0) में स्वयं इस सटीक परिदृश्य का उल्लेख ,8.12 में है, बिना किसी उल्लेख के volatile:

एक बेहतर तरीका यह है कि निजी स्टेटिक ऑब्जेक्ट को लॉक करके स्थिर डेटा तक पहुंच को सिंक्रनाइज़ किया जाए। उदाहरण के लिए:

class Cache
{
    private static object synchronizationObject = new object();
    public static void Add(object x) {
        lock (Cache.synchronizationObject) {
          ...
        }
    }
    public static void Remove(object x) {
        lock (Cache.synchronizationObject) {
          ...
        }
    }
}

अपने लेख में जॉन स्कीट ( yoda.arachsys.com/csharp/singleton.html ) का कहना है कि इस मामले में उचित मेमोरी बैरियर के लिए अस्थिरता की आवश्यकता होती है। मार्क, क्या आप इस पर टिप्पणी कर सकते हैं?
कोनस्टेंटिन

आह, मैंने डबल-चेक लॉक पर ध्यान नहीं दिया था; बस: कि ;-p ऐसा नहीं करते हैं
मार्क Gravell

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

लेकिन क्या यह उतना ही अच्छा है जितना अलग वर्ग के दृष्टिकोण में जॉन का उल्लेख है?
मार्क Gravell

-3

डबल चेक किए गए लॉकिंग के साथ अस्थिरता का उपयोग करने के बारे में यह एक बहुत अच्छा पोस्ट है:

http://tech.puredanger.com/2007/06/15/double-checked-locking/

जावा में, यदि उद्देश्य एक चर की रक्षा करना है जिसे आपको अस्थिर होने पर चिह्नित करने की आवश्यकता नहीं है


3
दिलचस्प है, लेकिन जरूरी नहीं कि बहुत उपयोगी हो। जेवीएम का मेमोरी मॉडल और सीएलआर का मेमोरी मॉडल एक ही बात नहीं है।
bcat
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.