मैंने volatile
कीवर्ड के बारे में कुछ लेख पढ़े लेकिन मैं इसका सही उपयोग नहीं कर पाया। क्या आप मुझे बता सकते हैं कि C # और Java में इसका क्या उपयोग होना चाहिए?
मैंने volatile
कीवर्ड के बारे में कुछ लेख पढ़े लेकिन मैं इसका सही उपयोग नहीं कर पाया। क्या आप मुझे बता सकते हैं कि C # और Java में इसका क्या उपयोग होना चाहिए?
जवाबों:
C # और Java दोनों के लिए, "अस्थिर" कंपाइलर को बताता है कि एक वैरिएबल के मूल्य को कभी भी कैश नहीं करना चाहिए क्योंकि इसका मान प्रोग्राम के दायरे से बाहर बदल सकता है। कंपाइलर तब किसी भी ऑप्टिमाइजेशन से बच जाएगा, जिसके परिणामस्वरूप चर "इसके नियंत्रण के बाहर" परिवर्तित होने पर समस्या हो सकती है।
इस उदाहरण पर विचार करें:
int i = 5;
System.out.println(i);
कंपाइलर इसे केवल 5 प्रिंट करने के लिए अनुकूलित कर सकता है, जैसे:
System.out.println(5);
हालांकि, अगर एक और धागा है जो बदल सकता है i
, तो यह गलत व्यवहार है। यदि एक और धागा i
6 हो जाता है, तो अनुकूलित संस्करण अभी भी 5 प्रिंट करेगा।
volatile
कीवर्ड ऐसे अनुकूलन और कैशिंग से बचाता है, और इस तरह से उपयोगी है जब एक चर एक और धागा द्वारा बदला जा सकता।
i
चिह्नित के रूप में मान्य होगा volatile
। जावा में यह सभी रिश्तों से पहले होता है ।
i
एक स्थानीय चर है, तो कोई भी अन्य धागा इसे बदल नहीं सकता है। यदि यह एक फ़ील्ड है, तो कंपाइलर कॉल को ऑप्टिमाइज़ नहीं कर सकता है जब तक कि यह न हो final
। मुझे नहीं लगता कि संकलक यह मानकर आधारित अनुकूलन कर सकता है कि कोई फ़ील्ड "दिखता है" final
जब इसे स्पष्ट रूप से घोषित नहीं किया जाता है।
यह समझने के लिए कि एक चर में क्या अस्थिर होता है, यह समझना महत्वपूर्ण है कि क्या होता है जब चर अस्थिर नहीं होता है।
जब दो धागे A & B एक गैर-वाष्पशील चर तक पहुंच रहे हैं, तो प्रत्येक धागा स्थानीय कैश में चर की एक स्थानीय प्रतिलिपि बनाए रखेगा। थ्रेड ए द्वारा स्थानीय थ्रेड में किए गए कोई भी परिवर्तन थ्रेड बी को दिखाई नहीं देंगे।
जब चरों को अस्थिर घोषित किया जाता है, तो इसका अनिवार्य रूप से मतलब होता है कि थ्रेड्स को ऐसे वैरिएबल को कैश नहीं करना चाहिए या दूसरे शब्दों में, थ्रेड्स को इन चरों के मूल्यों पर भरोसा नहीं करना चाहिए जब तक कि वे मुख्य मेमोरी से सीधे नहीं पढ़े जाते हैं।
तो, परिवर्तनशील अस्थिर कब बनाया जाए?
जब आपके पास एक चर होता है जिसे कई थ्रेड्स द्वारा एक्सेस किया जा सकता है और आप चाहते हैं कि हर थ्रेड उस वैरिएबल के नवीनतम अपडेटेड वैल्यू को प्राप्त करे, भले ही वैल्यू किसी अन्य थ्रेड / प्रोसेस / प्रोग्राम के बाहर अपडेट हो।
वाष्पशील क्षेत्रों के कारणों ने शब्दार्थ हासिल कर लिया है । इसका मतलब यह है कि यह गारंटी है कि वाष्पशील चर से पढ़ी गई मेमोरी किसी भी निम्न मेमोरी रीडिंग से पहले होगी। यह कंपाइलर को पुन: व्यवस्थित करने से रोकता है, और यदि हार्डवेयर को इसकी आवश्यकता होती है (कमजोर रूप से सीपीयू का आदेश दिया जाता है), यह हार्डवेयर को फ्लश पढ़ने के बाद होने वाली किसी भी रीड को फ्लश करने के लिए एक विशेष निर्देश का उपयोग करेगा, लेकिन सट्टा जल्दी शुरू किया गया था, या सीपीयू कर सकता था। लोड अधिग्रहित करने और इसकी सेवानिवृत्ति के बीच किसी भी सट्टा लोड को रोकने से, उन्हें पहले स्थान पर जल्दी जारी होने से रोकें।
वाष्पशील क्षेत्रों के लेखन में विमोचन शब्द हैं । इसका मतलब यह है कि यह गारंटी दी जाती है कि किसी भी मेमोरी को वाष्पशील चर पर लिखने की गारंटी दी जाती है, जब तक कि पिछली सभी मेमोरी राइट्स अन्य प्रोसेसर के लिए दिखाई न दें।
निम्नलिखित उदाहरण पर विचार करें:
something.foo = new Thing();
यदि foo
एक वर्ग में एक सदस्य चर है, और अन्य सीपीयू द्वारा संदर्भित ऑब्जेक्ट उदाहरण तक पहुंच है something
, तो वे मूल्य foo
परिवर्तन को देख सकते हैं इससे पहले कि Thing
निर्माणकर्ता में लिखी गई मेमोरी विश्व स्तर पर दिखाई दे! यह वह है जो "कमजोर रूप से आदेशित स्मृति" का अर्थ है। यह तब भी हो सकता है जब कंपाइलर में स्टोर से पहले कंस्ट्रक्टर के सभी स्टोर हों foo
। अगर foo
है volatile
तो दुकान में foo
रिलीज अर्थ विज्ञान होगा, और हार्डवेयर की गारंटी देता है लिखने से पहले राईट के सभी कि करने के लिए foo
लिखने के लिए अनुमति देने से पहले अन्य प्रोसेसर के लिए दिखाई दे रहे हैं foo
होने के लिए।
यह कैसे संभव है कि foo
लेखों को इतनी बुरी तरह से पुन: व्यवस्थित किया जा सके? यदि कैश लाइन होल्डिंग foo
कैश में है, और कंस्ट्रक्टर में स्टोर कैश से चूक गए हैं, तो स्टोर के लिए यह संभव है कि कैश मिस को लिखने की तुलना में बहुत जल्द पूरा हो जाए।
इंटेल से (भयानक) इटेनियम वास्तुकला ने कमजोर रूप से स्मृति का आदेश दिया था। मूल XBox 360 में उपयोग किए गए प्रोसेसर ने कमजोर रूप से मेमोरी का आदेश दिया था। बहुत ही लोकप्रिय ARMv7-A सहित कई एआरएम प्रोसेसर ने कमजोर रूप से स्मृति का आदेश दिया है।
डेवलपर्स अक्सर इन डेटा दौड़ को नहीं देखते हैं क्योंकि ताले जैसी चीजें एक पूर्ण मेमोरी अवरोध करती हैं, अनिवार्य रूप से एक ही समय में सिमेंटिक्स का अधिग्रहण और जारी करना। लॉक के अंदर कोई लोड सट्टा नहीं लगाया जा सकता है इससे पहले कि लॉक हासिल कर लिया जाए, उन्हें देरी हो जाती है जब तक कि लॉक हासिल नहीं हो जाता। लॉक रिलीज़ होने पर किसी भी स्टोर में देरी नहीं की जा सकती है, लॉक जारी करने वाले निर्देश में देरी हो रही है जब तक कि लॉक के अंदर किए गए सभी लेखन वैश्विक रूप से दिखाई नहीं देते हैं।
एक अधिक पूर्ण उदाहरण "डबल-चेकिंग लॉकिंग" पैटर्न है। इस पैटर्न का उद्देश्य किसी वस्तु को प्रारंभिक रूप से आलसी करने के लिए हमेशा लॉक का अधिग्रहण करने से बचना है।
स्नैग्ड
public class MySingleton {
private static object myLock = new object();
private static volatile MySingleton mySingleton = null;
private MySingleton() {
}
public static MySingleton GetInstance() {
if (mySingleton == null) { // 1st check
lock (myLock) {
if (mySingleton == null) { // 2nd (double) check
mySingleton = new MySingleton();
// Write-release semantics are implicitly handled by marking
// mySingleton with 'volatile', which inserts the necessary memory
// barriers between the constructor call and the write to mySingleton.
// The barriers created by the lock are not sufficient because
// the object is made visible before the lock is released.
}
}
}
// The barriers created by the lock are not sufficient because not all threads
// will acquire the lock. A fence for read-acquire semantics is needed between
// the test of mySingleton (above) and the use of its contents. This fence
// is automatically inserted because mySingleton is marked as 'volatile'.
return mySingleton;
}
}
इस उदाहरण में, स्टोर में MySingleton
स्टोर करने से पहले कंस्ट्रक्टर के स्टोर अन्य प्रोसेसर के लिए दृश्यमान नहीं हो सकते हैं mySingleton
। यदि ऐसा होता है, तो अन्य धागे जो मायसिंगलटन पर नज़र रखते हैं, वे एक ताला का अधिग्रहण नहीं करेंगे और वे आवश्यक रूप से निर्माणकर्ता को राइट्स नहीं लेंगे।
volatile
कैशिंग को कभी नहीं रोकता है। यह जो करता है वह उस आदेश की गारंटी देता है जिसमें अन्य प्रोसेसर "लिखते" लिखते हैं। एक स्टोर रिलीज़ एक स्टोर में देरी करेगा जब तक कि सभी लंबित राइट्स पूरे नहीं हो जाते हैं और एक बस चक्र जारी किया गया है ताकि अन्य प्रोसेसर को अपनी कैश लाइन को त्यागने / लिखने के लिए कहा जाए यदि वे संबंधित लाइनों को कैश करते हैं। एक लोड अधिग्रहण किसी भी अटकलें पढ़ता है, यह सुनिश्चित करेगा कि वे अतीत से बासी मान नहीं होंगे।
head
और tail
जरूरत संभालने से निर्माता को रोकने के लिए अस्थिर होने के लिए tail
परिवर्तन नहीं होगा, और यह मानते हुए से उपभोक्ता को रोकने के लिए head
नहीं बदलेगा। इसके अलावा, head
यह सुनिश्चित करने के लिए अस्थिर होना चाहिए कि कतार डेटा लिखता है जो विश्व स्तर पर स्टोर से पहले head
दिखाई दे रहा है।
अस्थिर कीवर्ड में दोनों जावा और सी # अलग अलग अर्थ है।
से जावा भाषा युक्ति :
एक क्षेत्र को अस्थिर घोषित किया जा सकता है, इस स्थिति में जावा मेमोरी मॉडल यह सुनिश्चित करता है कि सभी थ्रेड्स चर के लिए एक सुसंगत मूल्य देखें।
वाष्पशील कीवर्ड पर C # संदर्भ से :
वाष्पशील कीवर्ड इंगित करता है कि प्रोग्राम में किसी क्षेत्र को ऑपरेटिंग सिस्टम, हार्डवेयर, या समवर्ती रूप से निष्पादित थ्रेड जैसे कुछ द्वारा संशोधित किया जा सकता है।
जावा में, "अस्थिर" का उपयोग जेवीएम को यह बताने के लिए किया जाता है कि चर का उपयोग एक ही समय में कई थ्रेड द्वारा किया जा सकता है, इसलिए कुछ सामान्य अनुकूलन लागू नहीं किए जा सकते हैं।
विशेष रूप से स्थिति जहां एक ही चर पर पहुंचने वाले दो धागे एक ही मशीन में अलग-अलग सीपीयू पर चल रहे हैं। सीपीयू के आक्रामक रूप से डेटा को धारण करने के लिए यह बहुत आम है क्योंकि मेमोरी एक्सेस कैश एक्सेस की तुलना में बहुत धीमी है। इसका मतलब है कि यदि डेटा सीपीयू 1 में अपडेट किया गया है, तो इसे तुरंत सभी कैश के माध्यम से जाना चाहिए और इसके बजाय मुख्य मेमोरी में जाना चाहिए जब कैश खुद को साफ करने का फैसला करता है, ताकि सीपीयू 2 अपडेटेड वैल्यू (फिर से रास्ते में सभी कैश की उपेक्षा करके) देख सके।
जब आप ऐसे डेटा को पढ़ रहे होते हैं जो गैर-वाष्पशील होते हैं, तो निष्पादित थ्रेड हमेशा अद्यतन मान प्राप्त कर सकता है या नहीं भी कर सकता है। लेकिन अगर वस्तु अस्थिर है, तो थ्रेड को हमेशा सबसे अधिक मूल्य मिलता है।
अस्थिर समवर्ती समस्या को हल कर रहा है। उस मूल्य को सिंक में बनाने के लिए। यह कीवर्ड ज्यादातर थ्रेडिंग में उपयोग किया जाता है। जब एक ही चर को अद्यतन करने वाले कई थ्रेड।