2009-06-03 5 views
8

हर कोई जानता है कि यह सुरक्षित थ्रेड नहीं है:क्या सी # '??' है ऑपरेटर थ्रेड सुरक्षित?

public StringBuilder Builder 
{ 
    get 
    { 
     if (_builder != null) 
      _builder = new StringBuilder(); 
     return _builder; 
    } 
} 
इस बारे में

क्या?

public StringBuilder Builder 
{ 
    get { return _builder ?? (_builder = new StringBuilder()); } 
} 
+13

सी # विनिर्देश ध्यान से कॉल करता है कि कौन से ऑपरेशन परमाणु हैं; नल coalescing ऑपरेटरों परमाणु नहीं हैं। नल कोलेसिंग ऑपरेटर कोड के पहले हिस्से के लिए सिर्फ एक वाक्य रचनात्मक चीनी है। लेकिन आपको यहां बड़ी समस्याएं हैं; कौन सा परवाह करता है अगर फ़ील्ड थ्रेडसेफ है? निर्माता थ्रेडसेफ नहीं है! –

+4

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

उत्तर

10

संपादित शुरू

अपने संपादित शीर्षक के आधार पर, अशक्त-कोलेसिंग ऑपरेटर ही (Phil Haack's analysis देखें) धागे की सुरक्षित हो रहा है। हालांकि, ऐसा लगता है कि यह स्ट्रिंगबिल्डर निर्माता को संभावित एकाधिक कॉल के खिलाफ गारंटी नहीं देता है।

अंत संपादित

आप सूत्रण के साथ एक बड़ा समस्या है, और कहा कि कि बिल्डर संपत्ति ही कहा गया है कि धागे भर में साझा किया जा सकता का प्रतिनिधित्व करता है। भले ही आप आलसी प्रारंभिक धागे को सुरक्षित बनाते हैं, फिर भी कोई गारंटी नहीं है कि बिल्डर का उपभोग करने वाले तरीके इसे थ्रेड सुरक्षित तरीके से कर रहे हैं।

// below code makes the getter thread safe 
private object builderConstructionSynch = new object(); 
public StringBuilder Builder 
{ 
    get 
    { 
     lock (builderConstructionSynch) 
     { 
      if (_builder == null) _builder = new StringBuilder(); 
     } 
     return _builder; 
    } 
} 

ऊपर _builder की आलसी आरंभीकरण में सूत्रण समस्या को रोकने जाएगा, लेकिन जब तक आप StringBuilder के कहने तरीकों को अपने कॉल सिंक्रनाइज़, आप किसी भी तरीके कि बिल्डर संपत्ति का उपभोग में धागा सुरक्षा की गारंटी नहीं कर रहे हैं। ऐसा इसलिए है क्योंकि स्ट्रिंगबिल्डर में इंस्टेंस विधियों को थ्रेड सुरक्षित नहीं बनाया गया था। नीचे दिए गए पाठ को MSDN StringBuilder page से देखें।

किसी भी सार्वजनिक स्थिर इस प्रकार के सदस्यों (दृश्य बेसिक में साझा) धागा सुरक्षित हैं। कोई भी उदाहरण सदस्य थ्रेड सुरक्षित होने की गारंटी नहीं है।

यदि आप कई धागे में स्ट्रिंगबिल्डर का उपभोग कर रहे हैं, तो संभवत: आप अपनी कक्षा में इसे बेहतर ढंग से समेकित कर सकते हैं। बिल्डर को निजी बनाएं और बेनकाब क्या व्यवहार आप एक सार्वजनिक विधि के रूप में की जरूरत है:

public void AppendString(string toAppend) 
{ 
    lock (Builder) 
    { 
     Builder.Append(toAppend); 
    } 
} 

इस तरह आप हर जगह तुल्यकालन कोड लिखने नहीं कर रहे हैं।

+0

मैंने अभी सोचा था कि ?? परमाणु ऑपरेशन है। ? धागा भी सुरक्षित नहीं है? –

+3

मैं यह नहीं कह सकता कि नल-कोलेसिंग ऑपरेटर परमाणु है या नहीं, लेकिन मेरा दावा यह है कि आपको बड़ी समस्या है क्योंकि स्ट्रिंगबिल्डर आंतरिक रूप से थ्रेड-सुरक्षित नहीं है। –

+1

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

10

है यही कारण है कि कोई और अधिक या के लिए कम नहीं धागा सुरक्षित; आप अभी भी दो धागे एक ही समय में शून्य जांच कर सकते हैं, इस प्रकार अलग वस्तुओं को बना सकते हैं और दूसरे को नहीं देख सकते हैं।

+0

Interlocked.CompareExchange (रेफ _बिल्डर, नया स्ट्रिंगबिल्डर(), शून्य) का उपयोग करने की आपकी राय क्या है? – LBushkin

2

दिया उत्तर सही हैं, दोनों threadsafe नहीं कर रहे हैं। वास्तव में, वे अधिकतर समकक्ष होते हैं, और ?? ऑपरेटर कोड दुबला बनाने के लिए केवल कंपाइलर जादू है। यदि आप इसे थ्रेडसेफ बनना चाहते हैं तो आपको कुछ सिंक्रनाइज़ेशन तंत्र का उपयोग करने की आवश्यकता है।

2

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

using System.Threading; 

public StringBuilder Builder 
{ 
    get 
    { 
     if (_builder != null) 
      Interlocked.CompareExchange(ref _builder, new StringBuilder(), null); 
     return _builder; 
    } 
} 

तुलना एक्सचेंज() पर कॉल _builder में मूल्य के परमाणु प्रतिस्थापन को केवल स्ट्रिंगबिल्डर के नए उदाहरण के साथ ही करेगा यदि _builder == null।इंटरलाक्ड क्लास के सभी तरीकों को थ्रेड स्विच द्वारा प्रीमिट करने की गारंटी नहीं है।

+0

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