2009-01-12 15 views
27

स्ट्रिंग इन सी # अपरिवर्तनीय और थ्रेडसेफ हैं। लेकिन जब आपके पास सार्वजनिक गेटर संपत्ति होती है तो क्या होता है? इस तरह:एक स्ट्रिंग संपत्ति खुद थ्रेडसेफ है?

public String SampleProperty{ 
    get; 
    private set; 
} 

हम दो धागे है और पहले 'प्राप्त' बुला रहा है और दूसरे को "एक ही" समय में 'सेट' है, तो क्या होगा?

IMHO सेट इस तरह धागे की सुरक्षा के लिए एक ताला बनाया जाना चाहिए: परमाणु होने की गारंटी तो वहाँ

private string sampleField; 
private object threadSafer = new object(); 

public String SampleProperty{ 
    get{ return this.sampleField; } 
    private set{ 
     lock(threadSafer){ 
      sampleField = value; 
     } 
    } 
} 
+0

"आवश्यकता" है: संपत्ति के उपयोग (पढ़ने) के सभी धागे एक ही/सबसे अद्यतित मूल्य होना चाहिए। लेकिन केवल वस्तु ही मूल्य को संशोधित करती है। कीवर्ड 'अस्थिर' को इसकी गारंटी देनी चाहिए, या नहीं? – TomTom

उत्तर

37

अधिकांश उत्तर "परमाणु" शब्द का उपयोग कर रहे हैं जैसे कि परमाणु परिवर्तन की आवश्यकता होती है। वे आमतौर पर नहीं हैं।

टिप्पणियों में इसका उल्लेख किया गया है, लेकिन आम तौर पर उत्तर में नहीं - यह मेरा उत्तर देने का एकमात्र कारण है।

आमतौर पर आप एक पढ़ने धागा चर/संपत्ति के नवीनतम मूल्य देखना चाहते हैं (एक मोटे के विवरण का स्तर पर ताला लगा, जोड़कर तरह बातें की अनुमति देने के बारे में बात, पूरी तरह से वैध भी है।)। वह isn't guaranteed by atomicity। एक त्वरित उदाहरण के रूप में, यहाँ एक बुरा एक धागा बंद करने के लिए तरीका है:

पाश हमेशा के लिए
class BackgroundTaskDemo 
{ 
    private bool stopping = false; 

    static void Main() 
    { 
     BackgroundTaskDemo demo = new BackgroundTaskDemo(); 
     new Thread(demo.DoWork).Start(); 
     Thread.Sleep(5000); 
     demo.stopping = true; 
    } 

    static void DoWork() 
    { 
     while (!stopping) 
     { 
       // Do something here 
     } 
    } 
} 

DoWork हो सकता है अच्छी तरह से, बूलियन चर परमाणु होने के लिखने के बावजूद - के मूल्य को संचित करने से JIT रोकने के लिए कुछ नहीं है stoppingDoWork में। इसे ठीक करने के लिए, आपको या तो लॉक करने की आवश्यकता है, परिवर्तनीय volatile बनाएं या एक स्पष्ट मेमोरी बाधा का उपयोग करें। यह सब स्ट्रिंग गुणों पर भी लागू होता है।

+0

ग्रेट। मैं यही सुनना चाहता था। – TomTom

15

एक संदर्भ-प्रकार फ़ील्ड के प्राप्त/सेट (ldfld/stfld) है (IIRC) यहां भ्रष्टाचार का कोई खतरा नहीं होना चाहिए। तो यह कि कोण से धागा सुरक्षित होना चाहिए, लेकिन व्यक्तिगत रूप से मैं एक उच्च स्तर पर डेटा ताला चाहते हैं - यानी

lock(someExternalLock) { 
    record.Foo = "Bar"; 
} 

या हो सकता है: आप एक से अधिक बनाने के लिए

lock(record.SyncLock) { 
    record.Foo = "Bar"; 
} 

यह अनुमति देता है उसी ऑब्जेक्ट पर एक परमाणु ऑपरेशन के रूप में पढ़ता/अपडेट करता है, ताकि अन्य धागे को अमान्य ऑब्जेक्ट-स्टेट

+0

टॉमटॉम: जैसा कि एंड्रियास ह्यूबर ने मेरे उत्तर में एक टिप्पणी में बताया, लॉकिंग आपके द्वारा स्वचालित रूप से होती है, हालांकि यह आपको उस बिंदु से सुरक्षित नहीं रखेगी जहां दो धागे संपत्ति को संशोधित करने का प्रयास करते हैं, यही कारण है कि मार्क ने संपत्ति को लॉक करने का प्रस्ताव रखा है (उच्च स्तर), क्षेत्र (निचला स्तर) नहीं। –

+0

(ऑफ-विषय, लेकिन मैं उस डाउनवोट को कभी दान करने वाले फीडबैक का स्वागत करता हूं; मैं इसे व्यक्तिगत रूप से नहीं लेगा - अगर उत्तर में कोई समस्या है, तो कृपया मुझे बताएं) –

+0

मार्क: मेरी "आवश्यकता" है कि सभी धागे जो सिर्फ मूल्य को पढ़ते हैं, हमेशा सबसे अद्यतित मूल्य रखते हैं। केवल "उत्पत्ति" ऑब्जेक्ट को मान में हेरफेर करना चाहिए (निजी सेटर के पहले)। तो कीवर्ड 'अस्थिर' मेरी जरूरतों को पूरा करना चाहिए। उम्मीद है कि। – TomTom

4

स्ट्रिंग सेट करना एक परमाणु ऑपरेशन है, यानी आप या तो एन प्राप्त करेंगे ईडब्ल्यू स्ट्रिंग या पुरानी स्ट्रिंग, आपको कभी कचरा नहीं मिलेगा।

यदि आप कुछ काम कर रहे हैं उदा।

obj.SampleProperty = "Dear " + firstName + " " + lastName; 

तो स्ट्रिंग concatination सब होता है कॉल स्थापित करने के लिए पहले, इसलिए sampleField हमेशा या तो नए स्ट्रिंग या पुराने हो जाएगा।

यदि आपका स्ट्रिंग संगतता कोड स्वयं रेफरेंसियल है उदा।

obj.SampleProperty += obj.SampleProperty + "a"; 

और बाकी जहां एक और धागा पर आप

obj.SampleProperty = "Initial String Value"; 

तो फिर तुम ताला की जरूरत है।

विचार करें कि आप एक int के साथ काम कर रहे हैं। यदि आप int को असाइन कर रहे हैं, और int से प्राप्त कोई भी मान मान्य है, तो आपको इसे लॉक करने की आवश्यकता नहीं है।

हालांकि, अगर int सटीक होने के लिए, दो या दो से अधिक धागे द्वारा संसाधित विगेट्स की संख्या की गणना कर रहा है, तो आपको int को लॉक करने की आवश्यकता है। तारों के लिए यह वही स्थिति है।

मुझे एहसास है कि मैंने इसे बहुत अच्छी तरह से समझाया नहीं है, उम्मीद है कि इससे मदद मिलती है।

धन्यवाद

BW

+1

ओपी द्वारा प्रस्तावित स्तर पर लॉकिंग आपको अप्रत्याशित परिणामों से obj.SampleProperty + = "a" के साथ सुरक्षित नहीं करेगा; इस ऑपरेशन के साथ संपत्ति प्राप्त करने के लिए एक लॉक लिया जाता है, फिर लॉक जारी किया जाता है, फिर एक नई स्ट्रिंग को "ए" के साथ बनाया जाता है, फिर स्ट्रिंग को सेट करने के लिए लॉक फिर से लिया जाता है। –

+0

अच्छा बिंदु, यह सच है। मुझे लगता है कि यह वह जगह है जहां मार्क ग्रेवल्स बिंदु संपत्ति को असाइनमेंट लॉक करने पर आता है, न कि क्षेत्र के लिए असाइनमेंट। + 1 से मार्क (ऐसा लगता है कि वह + 20k प्रतिनिधि पर एक कारण है) –

0

यह लॉक करने के लिए किसी भी आवश्यकता के बिना धागे-सुरक्षित है। स्ट्रिंग्स संदर्भ प्रकार हैं, इसलिए केवल स्ट्रिंग का संदर्भ संशोधित किया जा रहा है। संदर्भ एक प्रकार के परमाणु होने की गारंटी है (32 बिट सिस्टम पर Int32 और 64 बिट पर Int64)।

0

आपकी दूसरी कोड नमूने निश्चित रूप से सही नहीं है, क्योंकि ताले केवल वांछित प्रभाव जब वे सभी स्थानों में उपयोग किया जाता है, जहां चर पहुँचा जा सकता है (दोनों के लिए मिलता है और सेट), इसलिए get भी आवश्यकता होगी ताला।

हालांकि, जब इस तरह की संपत्ति के रूप में संदर्भ-प्रकार फ़ील्ड प्राप्त और सेट करते हैं, तो लॉक स्टेटमेंट जोड़ना कोई मूल्य नहीं जोड़ता है। पॉइंटर्स को असाइनमेंट को .NET पर्यावरण में परमाणु होने की गारंटी दी जाती है, और यदि एकाधिक धागे किसी संपत्ति को बदल रहे हैं तो आपके पास एक अंतर्निहित दौड़ स्थिति है (जहां थ्रेड अलग-अलग मान देख सकते हैं; यह समस्या हो सकती है या नहीं हो सकती है) तो वहां बहुत कम है लॉकिंग में बिंदु।

तो यह क्या करता है, कोड का पहला भाग ठीक है। लेकिन क्या आप वास्तव में बहु-थ्रेडेड एप्लिकेशन में अंतर्निहित दौड़ की स्थिति बनाना चाहते हैं, यह एक और मामला है।

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