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


जवाबों:


423

वाष्पशील, संकलक से कहता है कि वो कुछ भी ऑप्टिमाइज़ न करें जिसे वाष्पशील चर से करना है।

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

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

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;
}

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

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

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

   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;
    }

46
निजी तौर पर, मैं पूर्णांक आकार पसंद करूँगा कि हार्डवेयर के साथ बात करते समय int8 / int16 / int32 हो। हालांकि इसका अच्छा जवाब है;)
टोनीलो

22
हां, आपको चीजों को एक निश्चित रजिस्टर आकार के साथ घोषित करना चाहिए, लेकिन हे - यह सिर्फ एक उदाहरण है।
Nils Pipenbrinck

69
थ्रेडेड कोड में वाष्पशील की भी आवश्यकता होती है जब आप उस डेटा के साथ खेल रहे होते हैं जो संगणक संरक्षित नहीं होता है। और हाँ ऐसा करने के लिए वैध समय हैं, आप उदाहरण के लिए स्पष्ट संगामिति सुरक्षा की आवश्यकता के बिना एक थ्रेड सुरक्षित परिपत्र संदेश कतार लिख सकते हैं, लेकिन इसके लिए वाष्पशील की आवश्यकता होगी।
गॉर्डन Wrigley

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

17
@ टॉलोमिया: पूरी तरह से गलत। उदास 17 व्यक्तियों को यह पता नहीं है। वाष्पशील एक मेमोरी बाड़ नहीं है। यह केवल गैर-दृश्य साइड इफेक्ट्स की धारणा के आधार पर अनुकूलन के दौरान कोड एलिसन से बचने से संबंधित है ।
v.oddou

187

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


अस्त्तिव मे आना? मूल रूप से C ++ से उधार नहीं लिया गया था? खैर, मुझे याद है ...
वाक्यविन्यास

यह सभी के बारे में अस्थिर नहीं है - यह अस्थिरता के रूप में निर्दिष्ट किए जाने पर कुछ पुन
व्यवस्थित

4
@ फ़ेसब्रो: इसका उद्देश्य volatileयह था कि कंपाइलरों के लिए कोड ऑप्टिमाइज़ करना संभव हो सके, जबकि प्रोग्रामर अभी भी ऐसे अनुकूलन के बिना प्राप्त किए जाने वाले शब्दार्थ को प्राप्त कर सकेंगे। मानक के लेखकों को उम्मीद थी कि गुणवत्ता कार्यान्वयन, जो भी शब्दार्थ उपयोगी थे, उनके लक्ष्य प्लेटफार्मों और अनुप्रयोग क्षेत्रों को देखते हुए समर्थन करेंगे, और उम्मीद नहीं करते थे कि संकलक लेखक मानक के अनुरूप सबसे कम गुणवत्ता वाले शब्दार्थ की पेशकश करना चाहते हैं और 100% नहीं थे। बेवकूफ (ध्यान दें कि मानक के लेखक स्पष्ट रूप से तर्क में पहचानते हैं ...
सुपरकैट

1
... कि वास्तव में किसी भी उद्देश्य के लिए उपयुक्त होने के लिए पर्याप्त गुणवत्ता के बिना एक कार्यान्वयन के लिए यह संभव है, लेकिन उन्होंने इसे रोकने के लिए आवश्यक नहीं सोचा था)।
सुपरकैट

1
@ syntaxerror C ++ से कैसे लिया जा सकता है जब C C ++ (दोनों पहले रिलीज़ और पहले मानकों दोनों) से एक दशक से अधिक पुराना था?
phuclv

178

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

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

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

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


जब आप कहते हैं "संकलक को हर बार इसे लोड करने के लिए मजबूर किया जाता है, तो क्या यह तब होता है जब संकलक एक निश्चित चर का अनुकूलन करने का निर्णय लेता है और हम चर को अस्थिर नहीं घोषित करते हैं, रन समय में कुछ चर को सीपीयू रजिस्टर में लोड किया जाता है, स्मृति में नहीं। ?
अमित सिंह तोमर

1
@AmitSinghTomar इसका मतलब है कि यह क्या कहता है: हर बार जब कोड मूल्य की जांच करता है, तो उसे फिर से लोड किया जाता है। अन्यथा, संकलक को यह मानने की अनुमति है कि चर का संदर्भ नहीं लेने वाले कार्य इसे संशोधित नहीं कर सकते हैं, इसलिए सीजरबी का मानना ​​है कि उपरोक्त लूप सेट नहीं होता है quit, संकलक मानकर इसे निरंतर लूप में अनुकूलित कर सकता है। quitपुनरावृत्तियों के बीच परिवर्तित होने का कोई तरीका नहीं है । NB: यह वास्तव में वास्तविक थ्रेडसेफ़ प्रोग्रामिंग के लिए एक अच्छा विकल्प नहीं है।
अंडरस्कोर_ड

यदि छोड़ दिया वैश्विक चर है, तो संकलक लूप को सही नहीं करेगा, सही है?
पियरे जी।

2
@PierreG। नहीं, संकलक हमेशा मान सकता है कि कोड एकल-थ्रेडेड है, जब तक कि अन्यथा नहीं बताया गया हो। यही है, volatileया अन्य मार्करों की अनुपस्थिति में , यह मान लेगा कि लूप के बाहर कुछ भी नहीं है, यह वैरिएबल को एक बार संशोधित करने के बाद लूप में प्रवेश करता है, भले ही यह एक ग्लोबल वैरिएबल हो।
सीजरबी

1
@PierreG। हां, संकलन के लिए प्रयास extern int global; void fn(void) { while (global != 0) { } }करें gcc -O3 -Sऔर परिणामस्वरूप असेंबली फ़ाइल को देखें, मेरी मशीन पर यह करता है movl global(%rip), %eax; testl %eax, %eax; je .L1; .L4: jmp .L4, अगर वैश्विक शून्य नहीं है, तो यह एक अनंत लूप है। फिर जोड़ने का प्रयास करें volatileऔर अंतर देखें।
सीजरबी

60

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


30

आंद्रेई अलेक्जेंड्रेस्कु का यह लेख देखें, " अस्थिर - मल्टीथ्रेडेड प्रोग्रामर बेस्ट फ्रेंड "

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

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

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

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


क्या मानक निर्दिष्ट करता है कि क्या एक रीड को 'अवलोकन योग्य व्यवहार' माना जाता है अगर मूल्य का उपयोग कभी नहीं किया जाता है? मेरी धारणा यह है कि यह होना चाहिए, लेकिन जब मैंने दावा किया कि यह कहीं और था तो किसी ने मुझे प्रशस्ति पत्र के लिए चुनौती दी। यह मुझे लगता है कि किसी भी मंच पर जहां एक अस्थिर चर का एक पढ़ने का कोई प्रभाव हो सकता है, एक संकलक को आवश्यक कोड उत्पन्न करना चाहिए जो हर संकेत पढ़ने को एक बार ठीक करता है; उस आवश्यकता के बिना, कोड लिखना मुश्किल होगा जिसने रीड्स का एक पूर्वानुमान योग्य अनुक्रम उत्पन्न किया।
सुपरकैट

@ सुपरकैट: पहले लेख के अनुसार, "यदि आप किसी वैरिएबल पर वाष्पशील संशोधक का उपयोग करते हैं, तो कंपाइलर उस वैरिएबल को रजिस्टर में कैश नहीं करेगा - प्रत्येक एक्सेस उस वैरिएबल की वास्तविक मेमोरी लोकेशन को हिट करेगा।" इसके अलावा, c99 मानक के खंड ,6.7.3.6 में यह कहा गया है: "एक ऐसी वस्तु जिसके पास वाष्पशील-योग्य प्रकार है, को कार्यान्वयन के लिए अज्ञात तरीकों से संशोधित किया जा सकता है या अन्य अज्ञात दुष्प्रभाव हो सकते हैं।" इसका तात्पर्य यह है कि वाष्पशील चर को रजिस्टरों में कैश्ड नहीं किया जा सकता है और अनुक्रम बिंदुओं के सापेक्ष सभी रीड और राइट को निष्पादित किया जाना चाहिए, ताकि वे वास्तव में अवलोकन कर सकें।
रॉबर्ट एस। बार्न्स

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

"कंपाइलर को इसे एक रजिस्टर में कैश करने की अनुमति नहीं है" - अधिकांश आरआईएससी आर्किटैक्ट्स एई रजिस्टर-मशीनों, इसलिए किसी भी रीड-संशोधित-राइट को ऑब्जेक्ट को एक रजिस्टरों में कैश करना पड़ता है। volatileपरमाणुता की गारंटी नहीं देता है।
इस साइट के लिए बहुत ही ईमानदार

1
@ ओलाफ: किसी रजिस्टर में कुछ लोड करना कैशिंग के समान नहीं है। कैशिंग लोड या स्टोर की संख्या या उनके समय को प्रभावित करेगा।
सुपरकैट

28

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

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

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

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

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

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


19

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

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

समस्या यह है कि x+h-xआमतौर 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;

संकलक मजबूर करने के लिए स्मृति स्थान पढ़ने के लिए hh युक्त, एक अंतिम अनुकूलन अवसर forfeiting।


व्युत्पन्न फार्मूला का उपयोग करने hया करने hhमें क्या अंतर है? जब hhगणना की जाती है तो अंतिम सूत्र पहले वाले की तरह उपयोग करता है, जिसमें कोई अंतर नहीं होता है। शायद यह होना चाहिए (f(x+h) - f(x))/hh?
सर्गेई झूकोव

2
के बीच का अंतर hऔर hhवह यह है कि hhऑपरेशन से दो के कुछ नकारात्मक शक्ति को छोटा किया गया है x + h - x। इस मामले में, x + hhऔर xबिल्कुल अलग hh। आप अपने सूत्र को भी ले सकते हैं, यह एक ही परिणाम देगा, चूंकि x + hऔर x + hhसमान हैं (यह भाजक है जो यहां महत्वपूर्ण है)।
अलेक्जेंड्रे सी।

3
यह लिखने के लिए अधिक पठनीय तरीका नहीं होगा x1=x+h; d = (f(x1)-f(x))/(x1-x)? अस्थिर का उपयोग किए बिना।
सेर्गेई ज़ुकोव

कोई भी संदर्भ जो एक संकलक फ़ंक्शन की उस दूसरी पंक्ति को मिटा सकता है?
CoffeeTableEspresso

@ कॉफ़ीटेबलएस्प्रेसो: नहीं, क्षमा करें। जितना अधिक मैं फ़्लोटिंग पॉइंट के बारे में जानता हूँ, उतना ही मुझे विश्वास है कि कंपाइलर को केवल इसे ऑप्टिमाइज़ करने की अनुमति दी जाती है यदि विस्फोटक रूप से ऐसा कहा गया है, -ffast-mathया समकक्ष।
अलेक्जेंड्रे सी।

11

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

  1. कंपाइलर उन फ़ंक्शंस को ऑप्टिमाइज़ नहीं करेगा जो अस्थिर कीवर्ड के साथ परिभाषित चर का उपयोग करते हैं

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

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


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

10

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


10

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

मान लीजिए कि आपने मेमोरी I-O को तेजी से I / O के लिए फाइल किया है और वह फाइल पर्दे के पीछे बदल सकती है (जैसे कि फाइल आपके स्थानीय हार्ड ड्राइव पर नहीं है, लेकिन इसके बजाय दूसरे कंप्यूटर द्वारा नेटवर्क पर सेवा की जाती है)।

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

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

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


7

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


कोई भी संकलक "रैम में भौतिक पता" या "कैश को बायपास" करने के लिए अस्थिर नहीं लेता है।
जिज्ञासु

6

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

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


5

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

मैं कहूंगा, उसका उदाहरण इसके लिए उपयुक्त नहीं है volatilevolatileइसका केवल उपयोग किया जाता है: संकलक को उपयोगी और वांछनीय अनुकूलन करने से रोकना । यह थ्रेड सेफ, एटॉमिक एक्सेस या मेमोरी ऑर्डर के बारे में कुछ भी नहीं है।

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

    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 में मैप किया गया है)। डेटा और कमांड असाइनमेंट के बीच मेमोरी बैरियर की जरूरत होती है।


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

5

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

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

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


5

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


1
क्या इस उत्तर में कुछ नया है जिसका उल्लेख पहले नहीं किया गया है?
स्लफान

3

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


0

जैसा कि यहां कई लोगों द्वारा सुझाया गया है, वाष्पशील कीवर्ड का लोकप्रिय उपयोग वाष्पशील चर के अनुकूलन को छोड़ना है।

सबसे अच्छा फायदा जो दिमाग में आता है, और अस्थिरता के बारे में पढ़ने के बाद ध्यान देने योग्य है - एक के मामले में चर के वापस रोलिंग को रोकने के लिए longjmp। एक गैर-स्थानीय कूद।

इसका क्या मतलब है?

इसका सीधा सा मतलब है कि स्टैक अनइंडिंग करने के बाद अंतिम मूल्य बरकरार रखा जाएगा , कुछ पिछले स्टैक फ्रेम पर लौटने के लिए; आमतौर पर कुछ गलत परिदृश्य के मामले में।

चूँकि यह इस प्रश्न के दायरे से बाहर होगा, मैं setjmp/longjmpयहाँ विवरण में नहीं जा रहा हूँ , लेकिन इसके बारे में पढ़ने लायक है; और अंतिम मूल्य को बनाए रखने के लिए अस्थिरता सुविधा का उपयोग कैसे किया जा सकता है।


-2

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.