दिलचस्प पोस्ट
Socket.io में हैंडशेकडेटा के साथ कस्टम डेटा भेजें? अधिसूचना में प्रदर्शित आइकन नहीं: इसके बजाय सफेद वर्ग दिखाया गया है एंड्रॉइड बटन को अक्षम कैसे करें? ब्राउज़र पर वापस बटन अक्षम करना ORA-00054: संसाधन व्यस्त है और NOWAIT निर्दिष्ट या समय समाप्त होने के साथ समाप्त हो गया एंड्रॉइड कोर लाइब्रेरी त्रुटि ऑब्जेक्ट में JSON स्ट्रिंग को पार्स करने के लिए सरल सी # फ़ंक्शन क्या है? @ सिंक्रनाइज़ () क्या करता है? @ आस्पेक्ट पहलू के लिए स्प्रिंग आटोवर्ड बीन रिक्त है PHP में कॉल करने वाले पायथन आर में कॉपी-ऑन-संशोधित शब्दार्थ क्या है, और कैनोनिकल स्रोत कहां है? उप-वर्ग या समूह के साथ छोड़ दिया गया जिसके द्वारा एक तेज़ हो? पायथन में स्ट्रिंग से पूर्णांक मान कैसे प्राप्त करें? योजना में एक सूची में तत्व की घटना की गणना करें? क्यों लंगर टैग ऊंचाई और इसके तत्व की चौड़ाई नहीं ले करता है

सी में अस्थिर होने की आवश्यकता क्यों है?

सी में volatile आवश्यकता क्यों है? इसका क्या उपयो है? यह क्या होगा?

वेब के समाधान से एकत्रित समाधान "सी में अस्थिर होने की आवश्यकता क्यों है?"

वाष्पशील कम्पाइलर को वाष्पशील चर के साथ कुछ भी करने के लिए अनुकूल नहीं है।

इसका उपयोग करने के लिए केवल एक कारण है: जब आप हार्डवेयर के साथ इंटरफ़ेस करते हैं

मान लीजिए आपके पास हार्डवेयर का एक छोटा सा टुकड़ा है जो रैम में मैप किया गया है और उसके पास दो पते हैं: एक कमांड पोर्ट और एक डेटा पोर्ट:

 typedef struct { int command; int data; int isbusy; } MyHardwareGadget; 

अब आप कुछ कमांड भेजना चाहते हैं:

 void SendCommand (MyHardwareGadget * gadget, int command, int data) { // wait while the gadget is busy: while (gadget->isbusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command; } 

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

इसके चारों ओर जाने का तरीका पॉइंटर गैजेट को वाष्पशील के रूप में घोषित करना है। इस प्रकार संकलक को आपके द्वारा लिखी गई कार्य करने के लिए मजबूर किया जाता है। यह स्मृति असाइनमेंट को नहीं निकाल सकता है, यह रजिस्टरों में चर को कैश नहीं कर सकता और यह असाइनमेंट के क्रम को भी नहीं बदल सकता है:

यह सही संस्करण है:

  void SendCommand (volatile MyHardwareGadget * gadget, int command, int data) { // wait while the gadget is busy: while (gadget->isbusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command; } 

volatile लिए एक अन्य उपयोग संकेत हैंडलर है यदि आपके पास ऐसा कोड है:

 quit = 0; while (!quit) { /* very small loop which is completely visible to the compiler */ } 

कंपाइलर को नोटिस करने की अनुमति दी जाती है कि लूप बॉडी quit व्हेरिएबल को स्पर्श न करे और लूप को कुछ while (true) लूप में कनवर्ट करे। यहां तक ​​कि अगर quit परिवर्तन SIGINT और SIGTERM लिए संकेत हैंडलर पर सेट किया गया है; संकलक को यह पता करने का कोई तरीका नहीं है कि

हालांकि, अगर quit व्हेरिएबल को volatile घोषित किया जाता है, तो कंपाइलर को हर बार लोड करने के लिए मजबूर किया जाता है, क्योंकि इसे कहीं और संशोधित किया जा सकता है। यह वास्तव में आप इस स्थिति में चाहते हैं।

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

volatile कंपाइलर को बताता है कि आपके चर को अन्य तरीकों से बदला जा सकता है, उस कोड से, जो इसे एक्सेस कर रहा है। उदाहरण के लिए, यह एक I / O- मैप किए गए स्मृति स्थान हो सकता है। यदि इस तरह के मामलों में यह निर्दिष्ट नहीं है, तो कुछ वैरिएबल एक्सेस को अनुकूलित किया जा सकता है, उदाहरण के लिए, इसकी सामग्री को एक रजिस्टर में रखा जा सकता है, और स्मृति स्थान फिर से नहीं पढ़ा जाता है।

आंद्रेई अलेक्जेंडरको द्वारा इस आलेख को देखें, " अस्थिर – बहुप्रतीक्षित प्रोग्रामर का सबसे अच्छा दोस्त "

संकलक ऑप्टिमाइजेशन को रोकने के लिए अस्थिर कुंजीशब्द तैयार किया गया था जो कुछ अतुल्यकालिक घटनाओं की मौजूदगी में कोड को गलत प्रदान कर सकता था। उदाहरण के लिए, यदि आप अस्थायी रूप से एक आदिम चर घोषित करते हैं, तो संकलक को इसे एक रजिस्टर में कैश करने की अनुमति नहीं है – एक सामान्य अनुकूलन जो विनाशकारी होगा यदि वह चर एकाधिक थ्रेड्स के बीच साझा किया गया हो। तो सामान्य नियम है, यदि आपके पास प्राचीन प्रकार के वेरिएबल हैं जिन्हें एकाधिक धागे के बीच साझा किया जाना चाहिए, तो उन चर को अस्थिर घोषित करें। लेकिन आप वास्तव में इस कीवर्ड के साथ बहुत कुछ कर सकते हैं: आप इसे कोड को पकड़ने के लिए उपयोग कर सकते हैं जो धागा सुरक्षित नहीं है, और आप समय संकलन करने पर ऐसा कर सकते हैं। यह लेख दिखाता है कि यह कैसे किया जाता है; समाधान में एक सरल स्मार्ट पॉइंटर शामिल होता है जो कोड के महत्वपूर्ण वर्गों को क्रमबद्ध करने में आसान बनाता है।

लेख C और C++ दोनों पर लागू होता है

स्कॉट मेयेर्स और आंद्रेई एलेक्जेंड्रेस्को द्वारा " सी ++ और डबल-चेक लॉकिंग के संकट " लेख भी देखें:

इसलिए जब कुछ मेमोरी स्थान (जैसे मेमोरी मैप किए गए बंदरगाहों या आईएसआर [इंटरप्ट सर्विस रूटिन] द्वारा संदर्भित मेमोरी) से निपटने के लिए, कुछ अनुकूलन को निलंबित किया जाना चाहिए। ऐसे स्थानों के लिए विशेष उपचार को निर्दिष्ट करने के लिए अस्थिरता मौजूद है: विशेष रूप से: (1) एक वाष्पशील चर की सामग्री "अस्थिर" है (कम्पाइलर से अज्ञात द्वारा बदल सकती है), (2) सभी वाष्पशील आंकड़ों को लिखते हैं "अवलोकन" होते हैं ताकि वे को धार्मिक रूप से निष्पादित किया जाना चाहिए, और (3) वाष्पशील डेटा पर सभी कार्यों को क्रम में निष्पादित किया जाता है जिसमें वे स्रोत कोड में दिखाई देते हैं। पहले दो नियम उचित पढ़ना और लिखना सुनिश्चित करते हैं। पिछले एक आई / ओ प्रोटोकॉल के कार्यान्वयन की अनुमति देता है जो इनपुट और आउटपुट मिश्रण करते हैं I यह अनौपचारिक रूप से सी और सी ++ की अस्थिर गारंटी है।

मेरी सरल व्याख्या है:

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

उदाहरण के लिए:

 bool usb_interface_flag = 0; while(usb_interface_flag == 0) { // execute logic for the scenario where the USB isn't connected } 

उपरोक्त कोड से, संकलक को लगता है कि usb_interface_flag को 0 के रूप में परिभाषित किया गया है, और वह समय लूप में यह हमेशा के लिए शून्य हो जाएगा। ऑप्टिमाइज़ेशन के बाद, संकलक इसे हर while(true) रूप में मानता है, जिसके परिणामस्वरूप अनंत लूप होता है।

इन प्रकार के परिदृश्यों से बचने के लिए, हम ध्वज को अस्थिर के रूप में घोषित करते हैं, हम संकलक को कह रहे हैं कि यह मान बाहरी इंटरफ़ेस या प्रोग्राम के अन्य मॉड्यूल से बदला जा सकता है, अर्थात, कृपया इसे अनुकूलित नहीं करें। यह वाष्पशील के लिए उपयोग का मामला है

अस्थिरता के लिए सीमांत उपयोग निम्नलिखित है कहते हैं कि आप एक समारोह के संख्यात्मक डेरिवेटिव गणना करना चाहते हैं f :

 double der_f(double x) { static const double h = 1e-3; return (f(x + h) - f(x)) / h; } 

समस्या यह है कि x+hx आम तौर पर गोल के त्रुटियों के कारण h के बराबर नहीं होता है इसके बारे में सोचें: जब आप बहुत करीबी संख्या घटाते हैं, तो आप बहुत सारे महत्वपूर्ण अंकों को खो देते हैं जो व्युत्पन्न (1.00001 – 1) की गणना को बर्बाद कर सकते हैं। एक संभव समाधान हो सकता है

 double der_f2(double x) { static const double h = 1e-3; double hh = x + h - x; return (f(x + hh) - f(x)) / hh; } 

लेकिन आपके प्लेटफ़ॉर्म और कंपाइलर स्विच के आधार पर, उस फ़ंक्शन की दूसरी पंक्ति को आक्रामक रूप से अनुकूलन संकलक द्वारा मिटा दिया जा सकता है। तो आप इसके बजाय लिखते हैं

  volatile double hh = x + h; hh -= x; 

संकलक को एचएच युक्त स्मृति स्थान को पढ़ने के लिए बाध्य करने के लिए, एक अंतिम ऑप्टिमाइज़ेशन अवसर को जब्त कर।

मैं एक और परिदृश्य का उल्लेख करता हूं जहां वाष्पशील महत्वपूर्ण हैं

मान लीजिए कि आप तेजी से आई / ओ के लिए एक फ़ाइल मेमोरी-मैप कर सकते हैं और यह फ़ाइल परिदृश्य के पीछे बदल सकती है (उदाहरण के तौर पर फाइल आपके स्थानीय हार्ड ड्राइव पर नहीं है, बल्कि इसे दूसरे कंप्यूटर पर नेटवर्क पर रखा जाता है)।

यदि आप मेमोरी-मैप किए गए फ़ाइल का डेटा पॉइंटर्स के माध्यम से गैर-वाष्पशील वस्तुओं (स्रोत कोड स्तर पर) तक पहुंचते हैं, तो कंपाइलर द्वारा जेनरेट किए गए कोड को इसके बारे में जानकारी होने के बिना ही कई बार एक ही डेटा प्राप्त कर सकते हैं।

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

यदि आप सुरक्षा की परवाह करते हैं, और आपको चाहिए, यह विचार करने के लिए एक महत्वपूर्ण परिदृश्य है

दो उपयोग हैं यह विशेष रूप से एम्बेडेड विकास में अधिक बार उपयोग किया जाता है।

  1. कम्पाइलर उन कार्यों का अनुकूलन नहीं करेगा जो कि वेरिएबल का उपयोग करते हैं जो कि वाष्पशील कीवर्ड से परिभाषित होते हैं

  2. वाष्पशील का उपयोग रैम, रोम, आदि में सटीक स्मृति स्थानों तक पहुंचने के लिए किया जाता है … यह स्मृति-मैप किए गए उपकरणों को नियंत्रित करने, सीपीयू रजिस्टरों तक पहुंचने और विशिष्ट स्मृति स्थानों को ढूंढने के लिए अधिक बार उपयोग किया जाता है।

विधानसभा सूची के साथ उदाहरण देखें पुन: एंबेडेड डिवेलपमेंट में सी "अस्थिर" कीवर्ड का उपयोग

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

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

http://clinuxpro.com/volatile-in-c पर लेख भी देखें

विकी के बारे में सब कुछ volatile :

  • अस्थिर (कंप्यूटर प्रोग्रामिंग)

और लिनक्स कर्नल का डॉक्टर भी volatile बारे में एक उत्कृष्ट संकेतन बनाता है:

  • क्यों "अस्थिर" प्रकार वर्ग का उपयोग नहीं किया जाना चाहिए

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

यह कंपाइलर को चर के स्वत: बदलते मूल्यों की अनुमति नहीं देता है। एक वाष्पशील चर गतिशील उपयोग के लिए है

मेरी राय में, आपको volatile से बहुत ज्यादा उम्मीद नहीं करनी चाहिए उदाहरण के लिए, निल्स पिपेनब्रिंक के अत्यधिक वोट वाले उत्तर में उदाहरण को देखें।

मैं कहूंगा, उनका उदाहरण volatile के लिए उपयुक्त नहीं है। volatile लिए केवल प्रयोग किया जाता है: संकलक को उपयोगी और वांछनीय अनुकूलन करने से रोकें । यह धागा सुरक्षित, परमाणु पहुंच या स्मृति क्रम के बारे में कुछ भी नहीं है।

उस उदाहरण में:

  void SendCommand (volatile MyHardwareGadget * gadget, int command, int data) { // wait while the gadget is busy: while (gadget->isbusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command; } 

gadget->data = data से पहले gadget->command = command केवल कम्पाइलर द्वारा संकलित कोड में ही गारंटी दी जाती है समय चलने पर, प्रोसेसर अभी भी संभवतः प्रोसेसर आर्किटेक्चर के बारे में डेटा और कमांड असाइनमेंट को रेखांकित करता है। हार्डवेयर को गलत डेटा मिल सकता है (लगता है कि गैजेट हार्डवेयर I / O के लिए मैप किया गया है) डेटा और कमांड असाइनमेंट के बीच स्मृति बाधा की आवश्यकता होती है।