2011-05-06 11 views
6

मैंने Paint.Net plugin के साथ कुछ समस्या डीबग कर दी है और मैंने यादृच्छिक वर्ग के साथ कुछ समस्याएं ठोकर खाई हैं, जब कई धागे एक उदाहरण से एक विधि को कॉल करते हैं।यादृच्छिक मुद्दों के साथ रैंडम में समस्याएं?

कुछ अजीब कारणों से, ऐसा लगता है कि अगर मैं समवर्ती पहुंच को रोकता हूं, तो कॉल किए गए विधि को सिंक्रनाइज़ करके, मेरा रैंडम इंस्टेंस व्यवहार करना शुरू कर देता है ... यादृच्छिक रूप से (लेकिन बुरी भावना में)।

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

using System; 
using System.Threading; 
using System.Runtime.CompilerServices; 
namespace testRandom { 

    class RandTest { 
     static int NTIMES = 300; 

     private long ac=0; 

     public void run() { // ask for random number 'ntimes' and accumulate 
      for(int i=0;i<NTIMES;i++) { 
       ac+=Program.getRandInt(); 
       System.Threading.Thread.Sleep(2); 
      } 
     } 

     public double getAv() { 
      return ac/(double)NTIMES; // average 
     } 
    } 

    class Program 
    { 

     static Random random = new Random(); 
     static int MAXVAL = 256; 
     static int NTREADS = 200; 

     //[MethodImpl(MethodImplOptions.Synchronized)] 
     public static int getRandInt() { 
      return random.Next(MAXVAL+1); // returns a value between 0 and MAXVAL (inclusive) 
     } 

     public static void Main(string[] args)  { 
      RandTest[] tests = new RandTest[NTREADS]; 
      Thread[] threads = new Thread[NTREADS]; 
      for(int i=0;i<NTREADS;i++) { 
       tests[i]= new RandTest(); 
       threads[i] = new Thread(new ThreadStart(tests[i].run)); 
      } 
      for(int i=0;i<NTREADS;i++) threads[i].Start(); 
      threads[0].Join(); 
      bool alive=true; 
      while(alive) { // make sure threads are finished 
       alive = false; 
       for(int i=0;i<NTREADS;i++) { if(threads[i].IsAlive) alive=true; } 
      } 
      double av=0; 
      for(int i=0;i<NTREADS;i++) av += tests[i].getAv(); 
      av /= NTREADS; 
      Console.WriteLine("Average:{0, 6:f2} Expected:{1, 6:f2}",av,MAXVAL/2.0); 

      Console.Write("Press any key to continue . . . "); 
      Console.ReadKey(true); 
     } 
    } 
} 

एक उदाहरण ouput (ऊपर मूल्यों के साथ):

Average: 78.98 Expected:128.00 
Press any key to continue . . . 

यह कुछ ज्ञात समस्या है? सिंक के बिना कई धागे से यादृच्छिक वस्तु को कॉल करना गलत है?

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

+0

जब तक दस्तावेज़ दस्तावेज विरोध नहीं करता ई आप मान सकते हैं कि कोई भी वर्ग एकल उदाहरण तक पहुंचने वाले एकाधिक धागे का समर्थन करता है। – CodesInChaos

उत्तर

17

कुछ अजीब कारण

यह वास्तव में अजीब नहीं है के लिए - Random धागा सुरक्षित नहीं होने के लिए documented है।

यह दर्द है, लेकिन यह जीवन है। अधिक जानकारी के लिए मेरे article on Random देखें, और प्रति थ्रेड के उदाहरण के लिए सुझाव, एक ही बीज के साथ कई धागे में शुरू करने के खिलाफ गार्ड के साथ।

+0

आउच - वास्तव में एक दर्द। धन्यवाद – leonbloy

+1

जॉन के लेख को भी देखें, https://msmvps.com/blogs/jon_skeet/archive/2009/11/04/revisiting-randomness.aspx – Brian

8

Random कक्षा धागा सुरक्षित नहीं है।

docs से:

Any instance members are not guaranteed to be thread safe 
सिंक्रनाइज़ करना है जो सभी धागे ब्लॉक करने के लिए कारण होगा करने के बजाय

, ThreadStatic विशेषता को लागू करने का प्रयास करें।

+0

धन्यवाद। मैं अभी भी आश्चर्यचकित हूं कि यह मुद्दा इतनी विनाशकारी प्रतीत होता है - मुझे उम्मीद है कि यादृच्छिक मूल्यों की कुछ जोड़ी समवर्ती कॉल की कुछ जोड़ी के लिए 'गलत' होगी, लेकिन ऐसा लगता है कि यादृच्छिक वस्तु पूरी तरह से खराब हो जाती है, और इसके मुकाबले से बकवास। – leonbloy

1

यादृच्छिक थ्रेड सुरक्षित होने की गारंटी नहीं है: http://msdn.microsoft.com/en-us/library/system.random.aspx जब तक कि यह सार्वजनिक स्थिर न हो।

+2

स्पष्टीकरण के लिए: "सार्वजनिक स्थैतिक" यादृच्छिक वर्ग की विधि/संपत्ति को संदर्भित करता है - यादृच्छिक वस्तु के लिए नहीं – leonbloy

1

दुर्भाग्य से यह सही है, यादृच्छिक कक्षा का उपयोग करते समय सावधान रहना होगा।

यहाँ और अधिक विवरण, टिप्पणियों और इस विषय पर कोड नमूने के साथ दो ब्लॉग पोस्ट कर रहे हैं:

इस व्यवहार का भी बदतर बात यह है कि यह सिर्फ काम करना बंद है (यानी समस्या होने के बाद 'random.ext ....' विधियों से वापसी मान 0)

+0

"यह सिर्फ काम करना बंद कर देता है" यह सबसे बुरा हिस्सा क्यों है? आईएमओ यह सबसे अच्छा हिस्सा है। अन्यथा आप ध्यान नहीं देंगे कि आपका कोड टूटा हुआ है। – CodesInChaos

+0

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

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