2010-02-28 12 views
8

एक सी # संरचना धागा-सुरक्षित है?सी # structs धागा सुरक्षित हैं?

struct Data 
{ 
    int _number; 
    public int Number { get { return _number; } set { _number = value; } } 

    public Data(int number) { _number = number; } 
} 
एक और प्रकार में

:

उदाहरण के लिए अगर वहाँ एक है

class DadData 
{ 
    public Data TheData { get; set; } 
} 

संपत्ति के नाम पर है TheData, धागा सुरक्षित है?

+0

यह निर्भर करता है। आप संरचना के साथ क्या कर रहे हैं? – SLaks

+2

इसके अलावा, आपको एक परिवर्तनीय संरचना नहीं बनाना चाहिए। http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil – SLaks

+0

इस http://stackoverflow.com/questions/2353014/are-c-structs-thread-safe/2353051#2353051 के अनुसार तुम्हे करना चाहिए। –

उत्तर

8

नहीं, .NET में संरचनाएं आंतरिक रूप से थ्रेड-सुरक्षित नहीं हैं।

हालांकि, प्रति-मूल्य-मूल्य अर्थशास्त्र जो संरचनाओं को इस अभिसरण के लिए बहुत प्रासंगिकता है।

यदि आप अपने संरचनाओं को चारों ओर पास कर रहे हैं और उन्हें चर या पास-दर-मूल्य पैरामीटर (कोई रेफरी या आउट कीवर्ड) में किसी भी तरीके से असाइन नहीं कर रहे हैं तो कॉपी का उपयोग किया जा रहा है।

बेशक, इसका मतलब है कि प्रतिलिपि में किए गए कोई भी परिवर्तन मूल संरचना में प्रतिबिंबित नहीं होते हैं, लेकिन यह उन्हें चारों ओर गुजरने के बारे में पता होना चाहिए।

यदि आप संरचना को सीधे इस तरीके से एक्सेस कर रहे हैं जिसमें कॉपी-बाय-वैल्यू सेमेन्टिक्स शामिल नहीं हैं (उदाहरण के लिए एक स्थिर क्षेत्र का उपयोग करना जो संरचना का प्रकार है, और Marc Gravel points out in his answer के रूप में, कई अन्य तरीके हैं) एकाधिक धागे, तो आपको घटना की थ्रेड-सुरक्षा को ध्यान में रखना होगा।

+0

और इसे और भी खराब करने के लिए, यह तब भी * महान * सौदे पर निर्भर करता है चाहे आपका कोड * फ़ील्ड *, * * चर * या * संपत्ति * से बात करता हो। सौभाग्य से इस मामले में ऑटो-लागू संपत्ति ('दडाटा') इनमें से अधिकांश को हटा देती है। तो मैं सिर्फ पूर्णता के लिए इसका जिक्र कर रहा हूं ;- –

+0

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

-2

नहीं। यह थ्रेड-सुरक्षित क्यों होगा? यह सिर्फ डेटा है। यह जादू द्वारा थ्रेड-सुरक्षित नहीं बनता है।

1

struct किसी सामान्य फ़ील्ड या चर से अधिक थ्रेड-सुरक्षित नहीं है। यदि आपके पास कम से कम एक थ्रेड इसे संशोधित कर रहा है, और कम से कम एक और थ्रेड इसे किसी भी समय स्पर्श कर रहा है, तो आप अप्रत्याशित/अपरिभाषित व्यवहार के साथ समाप्त हो सकते हैं।

इसके अलावा, उत्परिवर्तनीय structs कोड गंध हैं। क्या class के बजाय struct होने के लिए आपको कुछ विशेष कारण हैं? क्या आपको इस डेटा के लिए मूल्य-प्रकार अर्थशास्त्र की आवश्यकता है?

9

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

struct Data 
{ 
    readonly int _number; 
    public int Number { get { return _number; } } 

    public Data(int number) { _number = number; } 
} 

तब हाँ; वह थ्रेड-सुरक्षित है। अन्य सभी मामलों में उत्तर "शायद नहीं" है।

भी ध्यान रखें कि atomicity नियम लागू होते हैं, तो एक भी पढ़ने या DadData.TheData को अद्यतन धागा सुरक्षित, यहां तक ​​कि अपरिवर्तनीय struct के साथ होना नहीं माना जा सकता। आप (विशेष रूप से oversized structs के लिए) एक धागा संरचना को पढ़ सकते हैं जबकि एक और धागा इसे फिर से लिखता है; सिंक्रनाइज़ेशन के बिना बुरी चीजें घटित होंगी (अंत में)।

0

विभिन्न धागे 'एक म्यूटेबल स्ट्रक्चर के विभिन्न सदस्यों के प्रत्यक्ष पढ़ने और लिखने से एक दूसरे के साथ हस्तक्षेप नहीं होगा। इंटरलॉक विधियों के माध्यम से एक ही सदस्य को विभिन्न धागे की पहुंच उन विधियों के अर्थशास्त्र के अनुसार व्यवहार करेगी। ये तथ्य म्यूटेबल structs को थ्रेड-सुरक्षित व्यवहार की अनुमति देने की अनुमति दे सकते हैं।

उत्परिवर्तनीय भंडारण स्थान जो ढांचे को धारण करते हैं, जो सीधे प्रतिस्थापन को छोड़कर उत्परिवर्तन का कोई साधन नहीं देते हैं, कोई थ्रेड-सुरक्षा प्रदान नहीं करते हैं, सिवाय इसके कि जहां एक संरचना में एक 32-बिट पूर्णांक या एक ऑब्जेक्ट संदर्भ होता है, पढ़ने का प्रयास एक ऐसा (एकल-आइटम) स्ट्रक्चर स्टोरेज स्थान उसी समय लिखा जा रहा है, जिसे पूरी तरह से पुराने डेटा या पूरी तरह से नए डेटा को पढ़ने की गारंटी है। ध्यान दें कि अपरिवर्तनीय structs के साथ किसी इंटरलॉक विधियों का उपयोग करना संभव नहीं है - यहां तक ​​कि structs जिनमें केवल एक पूर्णांक या ऑब्जेक्ट संदर्भ होता है।

0

नहीं, वे नहीं हैं। मैंने यह देखने के लिए बहुत आसान ऐप बनाया है कि क्या 10/10 निर्माता/उपभोक्ता थ्रेड समान संरचना चर का उपयोग कर रहे हैं। और अंत में आप डीबगर देखेंगे। ब्रेक(); मारा जाएगा। बैंक की शेष राशि कभी भी 0 मान से कम नहीं होनी चाहिए।

namespace StructThreadSafe 
{ 
    class Program 
    { 
     struct BankBalance 
     { 
      public decimal Balance { get; set; } 
     } 

     static void Main(string[] args) 
     { 
      BankBalance bankBalance = new BankBalance(); 
      bankBalance.Balance = 100; 
      List<Task> allTasks = new List<Task>(); 
      for (int q = 0; q < 10; q++) 
      { 
       Task producer = new Task(() => 
       { 
        for (int i = 0; i < 1000; i++) 
        { 
         if (bankBalance.Balance < 0) 
         { 
          if (Debugger.IsAttached) 
          { 
           Debugger.Break(); 
          } 
         } 
         bankBalance.Balance += 5; 
         Console.WriteLine("++Current Balance: " + bankBalance.Balance); 
         System.Threading.Thread.Sleep(100); 
        } 
       }); 
       allTasks.Add(producer); 
      } 
      for (int w = 0; w < 10; w++) 
      { 
       Task consumer = new Task(() => 
       { 
        for (int i = 0; i < 1000; i++) 
        { 
         if (bankBalance.Balance < 0) 
         { 
          if (Debugger.IsAttached) 
          { 
           Debugger.Break(); 
          } 
         } 
         if (bankBalance.Balance > 15) 
         { 
          bankBalance.Balance -= 15; 
          Console.WriteLine("--Current Balance: " + bankBalance.Balance); 
         } 
         else 
         { 
          Console.WriteLine("**Current Balance below minimum: " + bankBalance.Balance); 
         } 
         System.Threading.Thread.Sleep(100); 
        } 
       }); 
       allTasks.Add(consumer); 
      } 
      allTasks.ForEach(p => p.Start()); 
      Task.WaitAll(allTasks.ToArray()); 

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