2009-06-30 12 views
5

में अस्थिर विनिर्देश का उपयोग मल्टीथ्रेड प्रोग्रामिंग पर कई संसाधनों के माध्यम से जाने के दौरान, अस्थिर विनिर्देशक के संदर्भ में आम तौर पर आता है। यह स्पष्ट है कि इस कीवर्ड का उपयोग सी/सी ++ और जावा (संस्करण 1.4 और इससे पहले) में कम से कम एकाधिक धागे के बीच सिंक्रनाइज़ेशन प्राप्त करने का एक विश्वसनीय तरीका नहीं है। यहाँ विकिपीडिया सूची के रूप में विशिष्ट उपयोगों के इस विनिर्देशक (बताया गया हो कि बिना) है: -सी/सी ++/जावा

  1. स्मृति मैप किए गए उपकरणों
  2. setjmp के बीच चर का उपयोग करता है और longjmp
  3. संकेत में चर का उपयोग करता है की अनुमति देते हैं अनुमति देने के लिए उपयोग की अनुमति संचालकों
  4. व्यस्त इंतजार कर

मैं उपरोक्त उपयोगों में इस विनिर्देशक की भूमिका को देखने के लिए शुरू कर सकते हैं लेकिन जब से मैं अभी तक पूरी तरह से understandi की जरूरत नहीं है इन क्षेत्रों में से प्रत्येक का एनजी, मैं यह नहीं समझ सकता कि यह निर्दिष्टकर्ता इन उपयोगों में से प्रत्येक में वास्तव में कैसे व्यवहार करता है।

क्या कोई समझा सकता है?

+0

उत्तर के लिए धन्यवाद। उपर्युक्त सूचीबद्ध उपयोगों में वास्तव में अस्थिर कार्य करने के तरीके पर कोई इनपुट? – Ankur

उत्तर

6

चूंकि आप उन उपयोग मामलों में रुचि रखते हैं, इसलिए मैं पहले को समझाऊंगा। ध्यान दें कि यह एक सी/सी ++ परिप्रेक्ष्य से लागू होता है, यह सुनिश्चित नहीं है कि यह जावा में कैसे खेलता है, हालांकि मुझे सामान्य रूप से सी/सी ++ में अस्थिरता पर संदेह है और जावा का उपयोग पूरी तरह से अलग-अलग मामलों के लिए किया जाता है।

मेमोरी मैप किए गए डिवाइस परिधीय हैं जो प्रोसेसर एक विशेष बस के बजाए स्मृति के समान तरीके से संचार करता है।

मान लीजिए कि आपके पास मेमोरी मैप किए गए टाइमर के साथ थोड़ा हल्का है। आप 1 मेमोरी एड्रेस & पर लिखकर प्रकाश को चालू करते हैं, इसके आंतरिक टाइमर 5 सेकंड & के लिए नीचे गिना जाता है और प्रकाश स्थान को 0 पर रीसेट करता है। अब आप एक प्रोग्राम विकसित कर रहे हैं जिसे कुछ घटनाओं के बाद उस रोशनी को चालू करने की आवश्यकता है , और काउंटर की समाप्ति से पहले इसे कभी-कभी बंद कर दें। यदि आप अपने मेमोरी लोकेशन को लिखने के लिए नियमित चर (एक पॉइंटर या इस प्रकार के एप्लिकेशन के लिए संदर्भ होते हैं) का उपयोग करते हैं, तो कंपाइलर ऑप्टिमाइज़ेशन के कारण कई चीजें गलत हो सकती हैं।

आपको लगता है कि कई चर के साथ काम नहीं कर रहे हैं और आपको लगता है कि मूल्य का उपयोग कर किसी भी अन्य चर के बिना इसे बंद करने के बाद पर प्रकाश बदल रहे हैं और शीघ्र ही वहाँ - में कभी कभी संकलक कुल मिलाकर पहला काम से छुटकारा मिल जाएगा, या अन्य मामलों में यह प्रोसेसर रजिस्टरों & में कभी भी स्मृति को लिखने में मूल्य बनाए रखेगा। इन दोनों मामलों में, प्रकाश woudl कभी चालू नहीं है क्योंकि यह स्मृति कभी नहीं बदला गया था।

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

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

+0

धन्यवाद डीबी। बहुत अच्छा उदाहरण। – Ankur

2

यहां एक अच्छी व्याख्या है: http://en.wikipedia.org/wiki/Volatile_variable लेकिन थोड़ा सरलीकृत यह संकलक को बताता है कि यह नहीं मानना ​​चाहिए कि चर किसी अन्य व्यक्ति द्वारा नहीं पहुंचाया गया है और यह रजिस्ट्रार में इसे अनुकूलित करने और केवल रजिस्टर को अपडेट करना घातक है और वास्तविक भंडारण नहीं।

+0

यह जावा की तुलना में सी और सी ++ में अलग है, न ही आश्चर्यजनक रूप से। उदाहरण के लिए जावा में, यदि संकलक यह निर्धारित कर सकता है कि एक अस्थिरता केवल एक थ्रेड द्वारा उपयोग की जाती है, तो इसका इलाज किया जा सकता है जैसे कि यह अस्थिर नहीं था। –

+0

सही, मुझे लगता है कि वे विकिपीडिया में भी उल्लेख करते हैं। विनिर्देशक का उद्देश्य अभी भी उतना ही कम है। – Fredrik

-1

वोल्टाइल चर का उपयोग तब किया जाना चाहिए जब उस चर को कई धागे से एक्सेस किया जा सके और आप प्रत्येक निर्देश पर अपने कोड को उस चर के अद्यतन मूल्य प्राप्त करना चाहते हैं।

कंपाइलर्स आमतौर पर प्रत्येक बार स्मृति को प्राप्त करने के बजाय रजिस्टर में कोड और स्टोर चर को अनुकूलित करते हैं, अगर उन्हें कोई भी इसे अपडेट नहीं करता है।

लेकिन अस्थिरता का उपयोग करके आप संकलक को हर बार अद्यतन मूल्य प्राप्त करने के लिए मजबूर कर सकते हैं।

+1

यह सही नहीं है। 'अस्थिर' बस इतना संकलक बता रहा है कि "आपके नियंत्रण के कुछ पक्ष इस चर को संशोधित कर सकते हैं इसलिए इसे अनुकूलित न करें"। क्या होगा इसके बारे में आपको वास्तव में कोई अन्य गारंटी नहीं है। अन्य उत्तरों में दिए गए लिंक बताते हैं कि आपके द्वारा वर्णित 'अस्थिर' का उपयोग करना गलत क्यों है। –

+0

सीपीयू कैश पर विचार करें। सी सार मशीन सीपीयू कैश नहीं जानता है। इसके लिए, एक मान भंडारण में हो सकता है यदि यह केवल * एक * सीपीयू के सीपीयू कैश में है, उदाहरण के लिए। बहु थ्रेडेड ऐप्स के लिए, इस तरह के कैश का उपयोग करके "स्टोरेज" का अर्थ शून्य है। –

+0

@ रिचर्ड: सहमत।अस्थिर विनिर्देशक को कई धागे के बीच सिंक्रनाइज़ेशन प्राप्त करने के साधन के रूप में कभी भी उपयोग नहीं किया जाना चाहिए। – Ankur

12

आपका प्रश्न तकनीकी रूप से 'कीड़े की एक' के रूप में जाना जाता है! सी/सी ++ के लिए (मैं जावा पर टिप्पणी नहीं कर सकता)
आप संकलक को निर्देशित करने के निर्देश के रूप में अस्थिर रूप से सारांशित कर सकते हैं कि 'कृपया इसे अनुकूलित न करें' लेकिन पेशेवरों के बीच बहुत अधिक तर्क है, यह
क) At all useful for kernel level code < -संपादित प्रतिक्रिया
ख) Even implemented correctly by most compilers.

इसके अलावा के आधार पर स्पष्ट किया है कि क्या करने के लिए के रूप में, कभी मल्टी-थ्रेडेड प्रोग्रामिंग के लिए उसका उपयोग नहीं करते और here's a very good explanation as to why

= संपादित करें = दिलचस्प है, के लिए यह क्या लायक है डेनिस रिची था के खिलाफ यह शामिल किए जाने (और साथ ही स्थिरांक) है here

+1

यह ध्यान दिया जाना चाहिए कि "सभी उपयोगी" दस्तावेज़ लिनक्स कर्नेल पेपर से लिंक हैं। वह दस्तावेज़ लिनक्स कर्नेल में अस्थिर होने के बारे में बात करता है। नीचे, वे अभी भी अस्थिर के अच्छे उपयोग देते हैं, जो कई धागे से संबंधित नहीं हैं। अस्थिरता समझ में आता है और वहां अच्छा होता है (यदि संकलक सही ढंग से अस्थिर व्यवहार करता है), जैसे व्यस्त लूप में जहां चर उसी सीपीयू के एक इंटरप्ट हैंडलर में अद्यतन किया जाता है। कंपाइलर सिर्फ यह नहीं जान सकता कि इसे पढ़ने को अनुकूलित नहीं करना चाहिए या नहीं। आपका बिंदु यह "अस्थिर" जैसा लगता है पूर्ण बकवास है (भले ही मुझे पता है कि आप इसका इरादा नहीं कर सकते हैं) :) –

+0

@litb Yep fair point। मैं उस बिंदु को स्पष्ट कर दूंगा। मैं नहीं कहूंगा कि यह कुल बकवास था, सिर्फ सोचा था कि मैं यह इंगित करता हूं कि यह स्पष्ट कटौती नहीं है कि – zebrabox

+0

बिल्कुल मैं क्या कहने जा रहा था। एक स्पष्टीकरण यह है कि ऑप्टिमाइज़ेशन आमतौर पर एक रजिस्टर में मूल्य संग्रहीत कर रहा था, इसे वहां से पुन: उपयोग कर रहा था। अस्थिर कोड प्रत्येक पठन पर स्मृति से मान को फिर से पढ़ने के लिए मजबूर करता है और रजिस्टर में कैश किए गए मान पर भरोसा नहीं करता है। अब कंपाइलर्स बहुत सारे ऑप्टिमाइज़िंग को पुनर्लेखन कथन और उनके ऑर्डर को शामिल करते हैं, इसलिए स्मृति से मूल्य को फिर से पढ़ना पर्याप्त नहीं है यदि आप अन्य थ्रेड में अपडेट किए गए ऑर्डर पर भरोसा करते हैं, तो इसके साथ निपटने के लिए मेमोरी बाधाओं की आवश्यकता होती है। – iain

4

मैं हर्ब Sutter बहुत ही दिलचस्प है, खासकर कैसे अस्थिर सी ++, जावा और सी # .NET में व्यवहार किया जाता है के द्वारा इस DDJ लेख पाया विवरण।

Dr.Dobbs volatile vs. volatile

+0

धन्यवाद ओवन। अच्छा था। – Ankur

0

यह एक समय हो गया है के बाद से मैं सी किया है ++ और मैं वास्तव में उस भाषा में volatine की परिभाषा को याद नहीं है। लेकिन जावा भाषा विनिर्देश विशेष रूप से कहता है कि अस्थिरता का उद्देश्य एक चर के लिए बहु थ्रेडेड पहुंच को सुविधाजनक बनाना है।उद्धरण: "एक क्षेत्र को अस्थिर घोषित किया जा सकता है, इस मामले में जावा मेमोरी मॉडल (§17) यह सुनिश्चित करता है कि सभी धागे चर के लिए एक सतत मान देखें।" वे कहते हैं कि अस्थिर मूल्यों के संदर्भों को कोड में निर्दिष्ट क्रम में संतुष्ट होने की गारंटी दी जाती है, यानी यदि आप i और j अस्थिर घोषित करते हैं और फिर "++ i; ++ j" लिखते हैं, तो मैं वास्तव में, हमेशा जे से पहले वृद्धि होगी।

जावा में अस्थिरता का उपयोग करने के लिए मुझे याद करने का एकमात्र समय था जब मेरे पास एक थ्रेड संभवतः एक रद्द ध्वज स्थापित करना था और कुछ बड़े ऑपरेशन के माध्यम से लूपिंग और प्रत्येक बार लूप के माध्यम से रद्द ध्वज की जांच कर रहा था। जैसा कि मैंने उम्मीद की थी यह वास्तव में काम करता था।

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

1

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

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

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

2

वाष्पशील चर जावा में उपयोगी होते हैं (कम से कम जावा 5.0 के बाद से जहां उनके behaviour changed), ब्रायन गोएज़ अपनी पुस्तक "अभ्यास में जावा संगामिति" (JCIP) में कहते हैं - इस विषय पर आवश्यक पुस्तक (पृष्ठ 37):

सुनिश्चित करना है कि एक चर के लिए अद्यतन अन्य धागे

स्पष्ट तुल्यकालन भी इस लक्ष्य को हासिल कर सकते हैं करने के लिए जाहिर उगाया जाता है, लेकिन अक्सर हम नहीं हमेशा एक मूल्य के लॉक करना चाहते हैं।

// Works with acquire/release semantics for volatile 
// Broken under Java 1.4 and earlier semantics for volatile 
class Foo { 
    private volatile Helper helper = null; 
    public Helper getHelper() { 
     if (helper == null) { 
      synchronized(this) { 
       if (null == helper) 
        helper = new Helper(); 
      } 
     } 
     return helper; 
    } 

    // other functions and members... 
} 

यह अगर सहायक अस्थिर नहीं था काम नहीं होगा: डबल की जाँच की लॉकिंग क्लासिक इस बात का उदाहरण (Wikipedia से नकल) है।

अस्थिर चर का उपयोग गैर-लॉकिंग समवर्ती डेटास्ट्रक्चर को लागू करने के लिए भी किया जा सकता है, जैसे java.util.concurrent.ConcurrentHashMap (जो समवर्ती अद्यतनों और लॉकिंग के बिना पहुंच का समर्थन करता है - वोल्टाइल के उपयोग के लिए जेडीके स्रोत कोड देखें)।

जेसीआईपी में सामान्य रूप से डबल-चेक लॉकिंग, अस्थिर चर, और जावा समरूपता की अच्छी चर्चा है। जोशुआ ब्लोच द्वारा "प्रभावी जावा", दूसरा संस्करण, पढ़ने योग्य भी है।

यह भी ध्यान दें कि java.util.concurrent.atomic पैकेज में परमाणु चर समर्थित हैं। ये थ्रेड/प्रोसेसर में अस्थिर चर के समान तरीके से मूल्यों को बदलने की अनुमति देते हैं, लेकिन "तुलना और सेट" संचालन करने की अनुमति भी देते हैं, जिसका अर्थ यह है कि कुछ अतिरिक्त प्रकार के समवर्ती संचालन सुरक्षित रूप से लॉक किए बिना किए जा सकते हैं।

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