C # में अस्थिर कीवर्ड का उपयोग


88

मैं एक छोटे से कार्यक्रम को कोड करना चाहूंगा जो नेत्रहीन के व्यवहार को दिखाता है volatile कीवर्ड । आदर्श रूप से, यह एक ऐसा कार्यक्रम होना चाहिए जो एक गैर वाष्पशील स्थिर क्षेत्र के लिए समवर्ती पहुँच करता है और जिसके कारण गलत व्यवहार हो जाता है।

उसी प्रोग्राम में अस्थिर कीवर्ड को जोड़ने से समस्या को ठीक करना चाहिए।

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

क्या आपके पास इस विषय पर कोई विचार है? क्या आप जानते हैं कि एक साधारण डेमो ऐप में इस तरह की समस्या का अनुकरण कैसे किया जाता है? क्या यह हार्डवेयर पर निर्भर करता है?

जवाबों:


102

मैंने एक काम करने का उदाहरण हासिल किया है!

विकी से प्राप्त मुख्य विचार, लेकिन सी # के लिए कुछ बदलावों के साथ। विकी लेख C ++ के स्थिर क्षेत्र के लिए इसे प्रदर्शित करता है, यह ऐसा लगता है जैसे C # हमेशा स्थिर क्षेत्रों के लिए अनुरोधों का सावधानीपूर्वक संकलन करता है ... और मैं गैर स्थैतिक के साथ उदाहरण बनाता हूं:

यदि आप इस उदाहरण को रिलीज़ मोड में और डिबगर के बिना (यानी Ctrl + F5 का उपयोग करके) चलाते हैं, तो लाइन while (test.foo != 255)'जबकि (सत्य)' के अनुकूल हो जाएगी और यह प्रोग्राम कभी वापस नहीं आएगा। लेकिन volatileकीवर्ड जोड़ने के बाद , आपको हमेशा 'ओके' मिलता है।

class Test
{
    /*volatile*/ int foo;

    static void Main()
    {
        var test = new Test();

        new Thread(delegate() { Thread.Sleep(500); test.foo = 255; }).Start();

        while (test.foo != 255) ;
        Console.WriteLine("OK");
    }
}

5
.NET 4.0 पर परीक्षण किया गया, दोनों x86 और x64 - पुष्टि कर सकते हैं कि उदाहरण अभी भी लागू है। धन्यवाद! :)
रोमन स्टार्कोव

1
यह अच्छा है! मुझे कभी नहीं पता था कि जेआईटी इस तरह का अनुकूलन करता है और यह अस्थिरता इसे निष्क्रिय कर देती है।
usr

3
बस स्पष्ट होने के लिए, आप फू के घोषणा में "अस्थिर" कीवर्ड जोड़ रहे हैं, है ना?
जोकुल

21

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


6

यह वास्तव में एक गलती की बात नहीं है जब 'वाष्पशील' कीवर्ड निर्दिष्ट नहीं किया जाता है, और यह कि जब यह निर्दिष्ट नहीं किया गया है तो एक त्रुटि हो सकती है। आम तौर पर आप यह जानने जा रहे हैं कि यह संकलक से बेहतर मामला कब है!

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

यह व्यवहार वास्तव में C ++ के समान कीवर्ड नहीं है।

MSDN का यहाँ संक्षिप्त वर्णन है । यहाँ शायद वोलेटिलिटी, एटमॉसिटी और इंटरलॉकिंग के विषयों पर एक अधिक गहराई वाली पोस्ट है


4

C # में प्रदर्शित करना कठिन है, क्योंकि कोड एक वर्चुअल मशीन द्वारा अमूर्त है, इस प्रकार इस मशीन के एक कार्यान्वयन पर यह बिना किसी अस्थिर के सही काम करता है, जबकि यह दूसरे पर विफल हो सकता है।

विकिपीडिया पर एक अच्छा उदाहरण है कि इसे C में कैसे प्रदर्शित किया जाए।

C # में भी यही बात हो सकती है यदि JIT कंपाइलर यह निर्णय लेता है कि चर का मान वैसे भी नहीं बदल सकता है और इस तरह मशीन कोड बनाता है जो इसे अब और नहीं देखता है। यदि अब एक और धागा मूल्य बदल रहा था, तो आपका पहला धागा अभी भी लूप में पकड़ा जा सकता है।

एक और उदाहरण व्यस्त प्रतीक्षा है।

फिर से, यह C # के साथ भी हो सकता है, लेकिन यह वर्चुअल मशीन पर और JIT कंपाइलर (या इंटरप्रेटर पर निर्भर करता है, अगर इसमें कोई JIT नहीं है ... सिद्धांत रूप में, मुझे लगता है कि MS हमेशा एक JIT कंपाइलर का उपयोग करता है और मोनो का भी उपयोग करता है। एक; लेकिन आप इसे मैन्युअल रूप से अक्षम करने में सक्षम हो सकते हैं)।


4

यहाँ इस व्यवहार की सामूहिक समझ के लिए मेरा योगदान है ... यह ज्यादा नहीं है, बस एक प्रदर्शन (xkip के डेमो पर आधारित) जो एक अस्थिर छंद के व्यवहार को एक गैर-वाष्पशील (यानी "सामान्य") अंतर मूल्य, पक्ष द्वारा दिखाता है -बस, उसी कार्यक्रम में ... जो मुझे यह धागा मिल रहा था, वह मैं देख रहा था।

using System;
using System.Threading;

namespace VolatileTest
{
  class VolatileTest 
  {
    private volatile int _volatileInt;
    public void Run() {
      new Thread(delegate() { Thread.Sleep(500); _volatileInt = 1; }).Start();
      while ( _volatileInt != 1 ) 
        ; // Do nothing
      Console.WriteLine("_volatileInt="+_volatileInt);
    }
  }

  class NormalTest 
  {
    private int _normalInt;
    public void Run() {
      new Thread(delegate() { Thread.Sleep(500); _normalInt = 1; }).Start();
      // NOTE: Program hangs here in Release mode only (not Debug mode).
      // See: http://stackoverflow.com/questions/133270/illustrating-usage-of-the-volatile-keyword-in-c-sharp
      // for an explanation of why. The short answer is because the
      // compiler optimisation caches _normalInt on a register, so
      // it never re-reads the value of the _normalInt variable, so
      // it never sees the modified value. Ergo: while ( true )!!!!
      while ( _normalInt != 1 ) 
        ; // Do nothing
      Console.WriteLine("_normalInt="+_normalInt);
    }
  }

  class Program
  {
    static void Main() {
#if DEBUG
      Console.WriteLine("You must run this program in Release mode to reproduce the problem!");
#endif
      new VolatileTest().Run();
      Console.WriteLine("This program will now hang!");
      new NormalTest().Run();
    }

  }
}

ऊपर कुछ वास्तव में उत्कृष्ट संक्षिप्त व्याख्याएं हैं, साथ ही साथ कुछ महान संदर्भ भी हैं। मेरी मदद करने के लिए सभी के लिए धन्यवाद मेरे सिर के चारों ओर volatile(कम से कम यह जानने के लिए कि volatileमेरी पहली वृत्ति कहां थी पर भरोसा नहीं करना चाहिएlock चाहिए)।

चीयर्स, और सभी मछली के लिए धन्यवाद। कीथ।


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

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

नहीं, यह कोई नया प्रश्न नहीं है ... यह मूल प्रश्न पर समुदाय को वापस करने का प्रयास है ।


2

मैं जो अलबहारी द्वारा निम्नलिखित पाठ में आया जिसने मुझे बहुत मदद की।

मैंने स्टैटिक वाष्पशील क्षेत्र बनाकर उपरोक्त पाठ से एक उदाहरण पकड़ा, जिसे मैंने थोड़ा बदल दिया। जब आप volatileकीवर्ड हटाएंगे तो प्रोग्राम अनिश्चित काल के लिए ब्लॉक हो जाएगा। इस उदाहरण को रिलीज़ मोड में चलाएँ ।

class Program
{
    public static volatile bool complete = false;

    private static void Main()
    {           
        var t = new Thread(() =>
        {
            bool toggle = false;
            while (!complete) toggle = !toggle;
        });

        t.Start();
        Thread.Sleep(1000); //let the other thread spin up
        complete = true;
        t.Join(); // Blocks indefinitely when you remove volatile
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.