2012-02-23 10 views
7

मैं हमारे codebase में आज कुछ सिंगलटन कोड में पड़ गए और मैं अगर निम्नलिखित धागे की सुरक्षित था यकीन नहीं था:सी के Atomicity # वालों ऑपरेटर

if (_sentence != null) { 
     return _sentence; 
} 
else { 
    return (_sentence = new Sentence()); 
} 
:

public static IContentStructure Sentence{ 
    get { 
     return _sentence ?? (_sentence = new Sentence()); 
    } 
} 

इस बयान के बराबर है

मुझे विश्वास है कि ?? सिर्फ एक कंपाइलर चाल है और परिणामस्वरूप कोड अभी भी परमाणु नहीं है। दूसरे शब्दों में, दो या अधिक धागे को एक नई वाक्य में _sentence सेट करने और इसे वापस करने से पहले शून्य होने के लिए शून्य हो सकता है। सब सही है कि है

public static IContentStructure Sentence{ 
    get { 

     lock (_sentence) { return _sentence ?? (_sentence = new Sentence()); } 
    } 
} 

:

atomicity की गारंटी के लिए, हम कोड की कि बिट लॉक करने के लिए होगा?

+2

http://csharpindepth.com/Articles/General/Singleton.aspx – SLaks

+2

सिवाय इसके कि आप शून्य पर कुछ लॉक नहीं कर सकते हैं, इसलिए आपका समाधान कभी काम नहीं करेगा। – vcsjones

+0

अच्छा बिंदु। हाँ आपको लॉक करने के लिए एक और ऑब्जेक्ट बनाना होगा। अच्छी पकड़। – Adam

उत्तर

11

आप सही हैं; यह सब थ्रेड-सुरक्षित नहीं है।

1

Interlocked.CompareExchangenull के साथ ?? -esque ऑपरेशन जो परमाणु है, प्राप्त करने के लिए आप Interlocked.CompareExchange का उपयोग कर सकते हैं।

// I made up my own Sentence type 
Sentence current = null; 
var whenNull = new Sentence() {Text = "Hello World!"}; 

var original = Interlocked.CompareExchange(ref current, new Sentence() { Text = "Hello World!" }, null); 

Assert.AreEqual(whenNull.Text, current.Text); 
Assert.IsNull(orig); 

// try that it won't override when not null 
current.Text += "!"; 
orig = Interlocked.CompareExchange(ref current, new Sentence() { Text = "Hello World!" }, null); 

Assert.AreEqual("Hello World!!", current.Text); 
Assert.IsNotNull(orig); 
+0

इसका नकारात्मक पक्ष यह है कि आप प्रत्येक पास के लिए एक नया 'वाक्य' बनाते हैं, नहीं? –

+2

@DrewNoakes: आप सही हैं। तुलनात्मक विनिमय करने के लिए यह अधिक मूर्खतापूर्ण है यदि वर्तमान शून्य है। फिर एक बार जब आप वस्तु को दो बार बनाते हैं तो असंभव दौड़ में होता है। यदि ऑब्जेक्ट को कभी भी दो बार बनाने के लिए अस्वीकार्य है तो आप अन्य तकनीकों का उपयोग कर सकते हैं। –

+0

तो, आपको निम्न कार्य करने में सक्षम होना चाहिए: var x = current ?? Interlocked.CompareExchange (वर्तमान वर्तमान, नई वाक्य(), शून्य) ?? वर्तमान; –

15

मैं हमारे codebase में आज कुछ सिंगलटन कोड में भाग

आप अपने codebase भर में इस तरह के अस्पष्ट कोड है? यह कोड वही काम करता है:

if (_s == null) 
    _s = new S(); 
return _s; 

और पढ़ने के लिए लगभग एक हजार बार आसान है।

मुझे विश्वास है कि ?? केवल एक कंपाइलर चाल है और परिणामस्वरूप कोड अभी भी परमाणु नहीं है

आप सही हैं। सी # atomicity के निम्नलिखित की गारंटी देता है बनाता है:

पढ़ता है और निम्न डेटा प्रकारों के बारे में लिखते परमाणु कर रहे हैं: bool, चार, बाइट, sbyte, लघु, ushort, uint, int, नाव, और संदर्भ प्रकार के। इसके अलावा, पिछली सूची में अंतर्निहित प्रकार के साथ enum प्रकारों के पढ़ने और लिखने पर भी परमाणु हैं। लंबे, उलझन, डबल, और दशमलव, साथ ही उपयोगकर्ता द्वारा परिभाषित प्रकार सहित अन्य प्रकार के पढ़ और लिखते हैं, परमाणु होने की गारंटी नहीं है। उस उद्देश्य के लिए डिज़ाइन किए गए लाइब्रेरी फ़ंक्शंस के अलावा, वृद्धि या कमी के मामले में परमाणु पढ़ने-संशोधित-लेखन की कोई गारंटी नहीं है।

शून्य coalescing ऑपरेटर गारंटी की उस सूची पर नहीं है।

atomicity की गारंटी के लिए, हम कोड की कि बिट लॉक करने के लिए होगा:

lock (_sentence) { return _sentence ?? (_sentence = new Sentence()); } } }  

अच्छा आकाश नहीं। वह तुरंत दुर्घटनाग्रस्त हो जाता है!

  • बंद करो बहु कोड लिखने की कोशिश कर:

    सही बात करने के लिए में से एक है।

  • एक सिंगलटन एकमात्र के बारे में अपने पेज पर सुरक्षित सिंगलटन पैटर्न जॉन स्कीट दस्तावेजों में से एक का उपयोग कर लिखें।
  • Lazy<T> कक्षा का उपयोग करें।
  • उस चर को लॉक करने के लिए समर्पित ऑब्जेक्ट पर लॉक करें।
  • एक परमाणु परीक्षण और सेट करने के लिए एक इंटरलॉक तुलना एक्सचेंज का उपयोग करें।
संबंधित मुद्दे