यह था कि देखते हैं कि कैसे volatile
प्रोसेसर आप http://www.albahari.com/threading/part4.aspx और भी अधिक/देखने पर कोड चलाने के आधार पर भी अलग असर पड़ता है नेट मेमोरी मॉडल (कम से कम 2.0 के बाद से) को उस उदाहरण को अस्थिर घोषित करने की आवश्यकता नहीं है, क्योंकि लॉक एक पूर्ण मेमोरी बाड़ प्रदान करेगा। क्या यह मामला नहीं है, या मैं गलत जानकारी दी थी?
यह आवश्यक है। इसका कारण यह है कि आप lock
के बाहर instance
तक पहुंच रहे हैं। आइए मान लें कि आप volatile
को छोड़ दें और इस तरह की प्रारंभिक समस्या को पहले ही तय कर चुके हैं।
public class Foo
{
private static Foo instance;
private static readonly object padlock = new object();
public static Foo GetValue()
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
var temp = new Foo();
temp.Init();
instance = temp;
}
}
}
return instance;
}
private void Init() { /* ... */ }
}
कुछ स्तर पर सी # संकलक, JIT कम्पाइलर, या हार्डवेयर को एक निर्देश अनुक्रम कि दूर temp
चर का अनुकूलन और instance
चर से पहले Init
भाग गया है सौंपा करने के लिए कारण बनता है फेंकना सकता है। वास्तव में, यह कन्स्ट्रक्टर चलाने से पहले instance
असाइन कर सकता है। Init
विधि इस मुद्दे को स्पॉट करने में आसान बनाती है, लेकिन समस्या अभी भी निर्माता के लिए भी है।
यह वैध अनुकूलन है क्योंकि निर्देश लॉक के भीतर फिर से व्यवस्थित होने के लिए स्वतंत्र हैं। lock
मेमोरी बाधा उत्सर्जित करता है, लेकिन केवल Monitor.Enter
और Monitor.Exit
कॉल पर।
अब, यदि आप volatile
को छोड़ देते हैं तो कोड शायद हार्डवेयर और सीएलआई कार्यान्वयन के अधिकांश संयोजनों के साथ काम करेगा। इसका कारण यह है कि x86 हार्डवेयर में एक कड़ा मेमोरी मॉडल है और सीएलआर का माइक्रोसॉफ्ट का कार्यान्वयन भी काफी तंग है। हालांकि, इस विषय पर ईसीएमए विनिर्देश अपेक्षाकृत ढीला है जिसका मतलब है कि सीएलआई का एक और कार्यान्वयन अनुकूलन करने के लिए स्वतंत्र है जो माइक्रोसॉफ्ट वर्तमान में अनदेखा करना चुनता है। आपको कमजोर मॉडल के लिए कोड करना होगा जो एक सीएलआई जिटर हो सकता है, न कि हार्डवेयर जो ज्यादातर लोग ध्यान केंद्रित करते हैं। यही कारण है कि volatile
अभी भी आवश्यक है।
एकाधिक धागे के संबंध में केवल पढ़ने योग्य/पढ़ने योग्य नहीं है? यह मेरी समझ थी कि एक धागे पर, प्रभाव लगातार क्रम में होंगे, और यह कि में लॉक किसी भी अन्य धागे को अस्वस्थ होने से रोकने से रोक देगा। क्या मैं यहां भी ऑफ-बेस हूं?
हां। निर्देश पुनर्गठन केवल तब खेलता है जब एक से अधिक धागे एक ही स्मृति स्थान तक पहुंच रहे हैं। यहां तक कि सबसे कमजोर सॉफ़्टवेयर और हार्डवेयर मेमोरी मॉडल किसी भी तरह के अनुकूलन की अनुमति नहीं देंगे जो थ्रेड पर कोड निष्पादित करते समय डेवलपर के इरादे से व्यवहार को बदलता है। अन्यथा, कोई प्रोग्राम सही तरीके से निष्पादित नहीं होगा। मुद्दा यह है कि कैसे अन्य धागे देखते हैं कि उस धागे में क्या चल रहा है। अन्य धागे निष्पादन धागे से अलग व्यवहार को समझ सकते हैं। लेकिन, निष्पादन धागा हमेशा सही व्यवहार को समझता है।
नहीं, lock
सभी अपने आप से अन्य धागे को घटनाओं के एक अलग अनुक्रम को समझने से नहीं रोकेंगे। इसका कारण यह है कि निष्पादन थ्रेड lock
के अंदर दिए गए निर्देशों को डेवलपर के इरादे से अलग क्रम में निर्देशों को निष्पादित कर सकता है।यह केवल लॉक के प्रवेश और निकास बिंदु पर है कि स्मृति बाधाएं बनाई गई हैं। तो आपके उदाहरण में नए ऑब्जेक्ट का संदर्भ instance
को कन्स्ट्रक्टर चलाने से पहले भी सौंपा जा सकता है भले ही आपने lock
के साथ उन निर्देशों को लपेट लिया हो।
volatile
का उपयोग करना, दूसरे हाथ पर, कैसे lock
बर्ताव के अंदर कोड आम ज्ञान के बावजूद विधि की शुरुआत में instance
की प्रारंभिक जांच की तुलना में पर बड़ा प्रभाव डाला है। बहुत से लोग सोचते हैं कि प्रमुख मुद्दा यह है कि instance
अस्थिर पढ़ने के बिना बासी हो सकती है। यह मामला हो सकता है, लेकिन बड़ा मुद्दा यह है कि lock
के अंदर एक अस्थिर लेखन के बिना instance
एक उदाहरण का जिक्र कर सकता है जिसके लिए निर्माता अभी तक नहीं चला है। एक अस्थिर लेखन इस समस्या को हल करता है क्योंकि यह संकलक को instance
पर लिखने के बाद कन्स्ट्रक्टर कोड को स्थानांतरित करने से रोकता है। यही कारण है कि volatile
अभी भी आवश्यक है।
आप .NET 2.0 मेमोरी मॉडल के बारे में सही हैं। आपको 'अस्थिर' की आवश्यकता नहीं है (क्योंकि यह शायद ही कभी करता है जो आप चाहते हैं) और एक 'लॉक' वास्तव में एक पूर्ण बाड़ करता है। हालांकि, चूंकि चिबासिटी बताती है, जब थ्रेड-सुरक्षा की बात आती है, तो दौड़ की स्थिति को नजरअंदाज करना बहुत आसान होता है। – Steven