2012-12-26 13 views
6

मुझे सी # में कक्षाएं बनाने का त्वरित तरीका पसंद है, जहां हम आसानी से सदस्यों को प्राप्त करने और सेट कोड को लागू किए बिना सदस्यों को बना सकते हैं, लेकिन (जहां तक ​​मुझे पता है) वे थ्रेड सुरक्षित नहीं हैं!इस सी # कक्षा धागे को फिर से लिखने के बिना सुरक्षित बनाने का कोई तरीका?

public class SocksEntry 
{ 
    public int Int1 { get; set; } 
    public int Int2 { get; set; } 
} 

क्या सी # ऐसा करने के बिना थ्रेड सुरक्षा जोड़ने का एक आसान तरीका प्रदान करता है?

public class SocksEntry 
{ 
    protected object _lock = new object(); 

    // internal 
    private int _int1 = 0; 
    private int _int2 = 0; 

    // accessors 
    protected int Int1 
    { 
     get { lock (_lock) return _int1; } 
     set { lock (_lock) _int1 = value; } 
    } 

    protected int Int2 
    { 
     get { lock (_lock) return _int2; } 
     set { lock (_lock) _int2 = value; } 
    } 
} 

यह स्पष्ट रूप से पूरी कक्षा को गैर-थ्रेड सुरक्षित संस्करण की तुलना में बहुत बड़ा और दर्द बनाने के लिए बनाता है!

+0

शायद इसे देखना चाहें: http://www.codeproject.com/Articles/33559/Handy-wrapper-class-for-thread-safe-property-acces –

+1

संपत्ति में एम्बेडेड ताले के साथ आपका कोड एक्सेसर्स वास्तव में थ्रेड-सुरक्षित नहीं है, या तो। यदि वे विधियों को रेखांकित करते हैं, तो वे एकमात्र चीज आपको याद कर सकते हैं, लेकिन आप जिन परिचालनों को 'लॉकिंग' कर रहे हैं वे वास्तव में पहले से ही परमाणु परिचालन हैं। यह केवल उच्च स्तर के संचालन को लॉक करने के लिए समझ में आता है जिसमें कई राज्यों के समन्वय शामिल होते हैं। –

उत्तर

7

कक्षा धागा सुरक्षित बनाना आपके लिए कल्पना करने की तुलना में बहुत कठिन है। यह गेटर्स और सेटर्स के चारों ओर ताले लगाने के लिए पर्याप्त नहीं हो सकता है। तो सबसे अच्छा अभ्यास है कि कक्षा को थ्रेड सुरक्षित न करें और इस वर्ग के उपभोक्ता को जिम्मेदारी छोड़ दें ताकि उसे थ्रेड सुरक्षा की आवश्यकता हो। यदि उपभोक्ता को थ्रेड सुरक्षा की आवश्यकता नहीं है, तो बढ़िया है, तो आप एप्लिकेशन के प्रदर्शन को दंडित नहीं करेंगे क्योंकि आपने कक्षा में थ्रेड सुरक्षा को बिना किसी आवश्यकता के बनाया है। आपको क्यों लगता है कि .NET में 99.99% कक्षाएं थ्रेड-सुरक्षित नहीं हैं?

+0

क्या आप इसे प्रदर्शित कर सकते हैं या नहीं? – IamStalker

+2

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

+0

ओह, आपको याद आती है कि मैं एक थ्रेड सुरक्षित, समाधान देखना चाहता हूं। – IamStalker

1

एक शब्द में, नहीं।

स्वत: कार्यान्वित गुण बहुत अच्छे हैं, लेकिन जब कोई सीमाएं हिट करता है, तो यह है।

हालांकि, आप Visual Studio snippet (जैसे prop) बना सकते हैं जो आपके लिए बॉयलर-प्लेट कोड लिखेंगे।

0

मुझे लगता है कि धागा सुरक्षा की समस्या की बात कर रहे हैं कुछ इस तरह है:

public int Value { get; set; } 

public void Foo() 
{ 
    if (this.Value > 0) // Read the property and make a decision based on its present value 
    { 
     // Do something with the property, assuming its value has passed your test. 
     // Note that the property's value may have been changed by another thread between the previous line and this one. 
     Console.WriteLine(this.Value); 
    } 
} 

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

public int Value { get; set; } 

public void Foo() 
{ 
    int cachedValue = this.Value; 

    if (cachedValue > 0) 
    { 
     Console.WriteLine(cachedValue); 
    } 
} 

हालांकि, जरूरी है कि अपने app करने के लिए माना जाता है क्या के लिए सही नहीं होगा।

0

सबसे आसान और फिर एकमात्र एक सही दृष्टिकोण कक्षा immutable बनाने के लिए है, इसलिए केवल पढ़ने के लिए ऑपरेशन उपलब्ध हैं।

public sealed class SocksEntry 
{ 
    public int Int1 { get; private set; } 
    public int Int2 { get; private set; } 
} 

लेकिन अगर यह एक विशेष व्यापार इकाई के लिए संभव नहीं है - बेनकाब संपत्ति setters के बजाय कुछ व्यापार के तरीकों, तो यह पूरे विधि सिंक करने के लिए (लेन-देन लगता है) के बजाय प्रत्येक संपत्ति सेटर जो कभी कभी समझ में आता है की तुलना में बहुत आसान है alltogether

// lock entire business transaction if possible 
public void UpdateEntity(int a, int b) 
{ 
    lock (entityLock) 
    { 
     Int1 = a; 
     Int2 = b; 
    } 
}  
+1

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

+0

मुझे लगता है कि 'सूची ' के साथ आपका उदाहरण अपरिवर्तनीय वर्ग का उदाहरण नहीं है क्योंकि आपने कहा है कि आप अभी भी सूची – sll

+0

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

0

नेट स्मृति मॉडल में निर्धारित करते हैं, पढ़ता है और देशी पूर्णांक प्रकार से कम या अपने प्लेटफ़ॉर्म के सूचक के आकार के बराबर का लिखते हैं (यानी int 32-बिट, long 64-बिट पर पर) परमाणु कर रहे हैं । परमाणु मतलब है कि आप ताले का उपयोग किए बिना इसे पढ़ और लिख सकते हैं, और आप कभी भी अधूरा नहीं पढ़ेंगे या लिखेंगे (यानी लिखने के बीच आधे रास्ते) मूल्य।

हालांकि,।नेट गारंटी नहीं देता है कि लिखने को तुरंत अन्य धागे के लिए दृश्यमान किया जाएगा (जिसका अर्थ है कि आप थ्रेड ए में लिख सकते हैं, फिर थ्रेड बी में पढ़ सकते हैं, और अभी भी पुराना मान पढ़ सकते हैं)। X86 पर आपको आर्किटेक्चर के साथ तत्काल दृश्यता मिलती है, लेकिन अन्य प्लेटफ़ॉर्म पर आपको लिखने के बाद volatile फ़ील्ड या Thread.MemoryBarrier का उपयोग करने की आवश्यकता होती है। lock आपके लिए एक मेमोरी बाधा डालता है, इसलिए आपको इसके बारे में चिंता करने की आवश्यकता नहीं है।

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

तो संक्षेप में: lock काफी अधिक है - आप इससे छुटकारा पा सकते हैं यदि आप तत्काल दृश्यता की आवश्यकता है तो यह अस्थिर/बाधाओं का उपयोग करें।

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