2010-11-16 11 views
18

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

private static string mutex= "ABC"; 

internal static void Foo(Rpc rpc) 
{ 
    lock (mutex) 
    { 
     //do something 
    } 
} 

उत्तर

32

स्ट्रिंग्स (कोड से) ऐसा हो सकता है "interned"। इसका मतलब है कि "एबीसी" के सभी उदाहरण एक ही वस्तु को इंगित करते हैं। यहां तक ​​कि AppDomain एस में भी आप एक ही ऑब्जेक्ट (टिप के लिए थैक्स स्टीवन) को इंगित कर सकते हैं।

यदि आपके पास विभिन्न स्थानों से बहुत सारे स्ट्रिंग-म्यूटेक्स हैं, लेकिन एक ही पाठ के साथ, वे सभी एक ही ऑब्जेक्ट को लॉक कर सकते हैं।

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

यह उपयोग करने के लिए बेहतर है:

private static readonly object mutex = new object(); 

इसके अतिरिक्त, क्योंकि अपने स्ट्रिंग नहीं const या readonly है, तो आप इसे बदल सकते हैं। तो (सिद्धांत में) अपने म्यूटेक्स को लॉक करना संभव है। Mutex को किसी अन्य संदर्भ में बदलें, और फिर एक महत्वपूर्ण खंड दर्ज करें क्योंकि लॉक किसी अन्य ऑब्जेक्ट/संदर्भ का उपयोग करता है। उदाहरण:

private static string mutex = "1"; 
private static string mutex2 = "1"; // for 'lock' mutex2 and mutex are the same 

private static void CriticalButFlawedMethod() { 
    lock(mutex) { 
     mutex += "."; // Hey, now mutex points to another reference/object 
     // You are free to re-enter 
     ... 
    } 
} 
+0

धन्यवाद जीवीएस। लेकिन मैं सोच रहा था कि एक स्ट्रिंग प्रकार (स्ट्रिंग होने योग्य स्ट्रिंग) का उपयोग करके लॉक करने के लिए किसी ऑब्जेक्ट प्रकार (जिसे हम आम तौर पर करते हैं) का उपयोग करने में कोई अंतर होता है। इस कार्यक्रम में बड़ी संख्या में थ्रेड विवाद हैं (अभी तक सुनिश्चित नहीं है कि यह कोड के इस टुकड़े के कारण है)। – Illuminati

+0

स्ट्रिंग्स म्यूटेबल नहीं हैं, वे सिर्फ म्यूटेबल दिखते हैं, लेकिन प्रत्येक अलग स्ट्रिंग दूसरे संदर्भ में इंगित करती है। मुझे उन पर ताला लगाने के लिए अजीब लग रहा है। क्या आपने रीडरवाइटर लॉक को आजमाया था। – GvS

+0

क्षमा करें, मेरा मतलब है "स्ट्रिंग अपरिवर्तनीय" :) .. मैंने रीडरवाइटर लॉक के साथ प्रयास नहीं किया था .. केवल कोड के सटीक खंड को समझने की कोशिश कर रहा था जो मुद्दों का कारण बनता है। अपर्याप्त डेटा के कारण स्थानीय enviornment में situcation फिर से बनाना मुश्किल है। लेकिन मैं इसे पुनः उत्पादन में कुछ कोशिश करने जा रहा हूं। एक बार फिर धन्यवाद। – Illuminati

1

आप एक स्ट्रिंग लॉक करने के लिए की जरूरत है, आप एक वस्तु बना सकते हैं कि जोड़े के एक वस्तु है कि आप के साथ लॉक कर सकते हैं के साथ स्ट्रिंग।

class LockableString 
{ 
    public string _String; 
    public object MyLock; //Provide a lock to the data in. 

    public LockableString() 
    { 
      MyLock = new object(); 
    } 
} 
14

आपके प्रश्न का उत्तर करने के लिए (के रूप में कुछ अन्य लोगों के पहले से ही है), वहाँ कोड उदाहरण आपके द्वारा दी गई कुछ संभावित समस्याओं हैं:

private static string mutex= "ABC"; 
  • चर mutex अपरिवर्तनीय नहीं है।
  • स्ट्रिंग शाब्दिक "ABC" आपके एप्लिकेशन में हर जगह एक ही इंटर्न वाले ऑब्जेक्ट संदर्भ को संदर्भित करेगा।

सामान्य रूप से, मैं स्ट्रिंग पर लॉकिंग के खिलाफ सलाह दूंगा। हालांकि, एक ऐसा मामला है जहां मैंने भाग लिया है जहां यह करने के लिए उपयोगी है।

ऐसे मौके हैं जहां मैंने लॉक ऑब्जेक्ट्स का एक शब्दकोश बनाए रखा है जहां कुंजी मेरे पास कुछ डेटा के बारे में कुछ अद्वितीय है।

void Main() 
{ 
    var a = new SomeEntity{ Id = 1 }; 
    var b = new SomeEntity{ Id = 2 }; 

    Task.Run(() => DoSomething(a));  
    Task.Run(() => DoSomething(a));  
    Task.Run(() => DoSomething(b));  
    Task.Run(() => DoSomething(b)); 
} 

ConcurrentDictionary<int, object> _locks = new ConcurrentDictionary<int, object>();  
void DoSomething(SomeEntity entity) 
{ 
    var mutex = _locks.GetOrAdd(entity.Id, id => new object()); 

    lock(mutex) 
    { 
     Console.WriteLine("Inside {0}", entity.Id); 
     // do some work 
    } 
} 

इस तरह कोड के लक्ष्य इकाई के Id के संदर्भ में DoSomething() के समवर्ती आमंत्रण क्रमानुसार करने है: यह एक काल्पनिक उदाहरण है। नकारात्मक शब्दकोष है। वहां जितनी अधिक इकाइयां होती हैं, उतनी ही बड़ी होती है। यह पढ़ने और सोचने के लिए भी और अधिक कोड है।

मुझे लगता है।नेट की स्ट्रिंग होना शामिल चीजों को आसान बनाने में कर सकते हैं:

void Main() 
{ 
    var a = new SomeEntity{ Id = 1 }; 
    var b = new SomeEntity{ Id = 2 }; 

    Task.Run(() => DoSomething(a));  
    Task.Run(() => DoSomething(a));  
    Task.Run(() => DoSomething(b));  
    Task.Run(() => DoSomething(b)); 
} 

void DoSomething(SomeEntity entity) 
{ 
    lock(string.Intern("dee9e550-50b5-41ae-af70-f03797ff2a5d:" + entity.Id)) 
    { 
     Console.WriteLine("Inside {0}", entity.Id); 
     // do some work 
    } 
} 

यहाँ अंतर यह है कि मैं स्ट्रिंग मुझे इकाई आईडी प्रति एक ही वस्तु संदर्भ देने के लिए होना शामिल पर भरोसा कर रहा हूँ। यह मेरे कोड को सरल बनाता है क्योंकि मुझे mutex उदाहरणों के शब्दकोश को बनाए रखने की आवश्यकता नहीं है।

हार्ड-कोडित यूयूआईडी स्ट्रिंग पर ध्यान दें जिसे मैं नामस्थान के रूप में उपयोग कर रहा हूं। यह महत्वपूर्ण है यदि मैं अपने आवेदन के किसी अन्य क्षेत्र में तारों पर लॉकिंग के समान दृष्टिकोण को अपनाना चुनता हूं।

स्ट्रिंग्स पर लॉक करना परिस्थितियों और ध्यान के आधार पर डेवलपर विवरण के आधार पर एक अच्छा विचार या बुरा विचार हो सकता है।

+0

यह उत्तर वास्तव में मैं जो खोज रहा था वह था। मुझे एक गारंटी की आवश्यकता है कि एक ही स्ट्रिंग एक ही म्यूटेक्स ऑब्जेक्ट करेगी और स्ट्रिंग इंटर्निंग उस के लिए उपयोग करने के लिए एक बहुत साफ तंत्र है। मुझे इसे कैशिंग के उद्देश्यों के लिए चाहिए: एकाधिक थ्रेड डीबी से एक ही ऑब्जेक्ट को पुनः प्राप्त कर सकते हैं और उन्हें कैश में केवल 1 प्रविष्टि डालना होगा, जिसमें "आईडी" की कुंजी है। तो अब मैं सिर्फ इस आईडी से लॉक करने के लिए एक स्ट्रिंग का निर्माण करता हूं और कुछ मनमानी स्ट्रिंग जो कभी भी कहीं भी कभी भी उपयोग नहीं की जाएगी (कुछ ऐसे लोगों के लिए जो कि अपेक्षाकृत सुरक्षित होना चाहते हैं), और इस लॉक में ऑब्जेक्ट इंस्टेंटेशन और कैश अपडेट करें। – evilkos

+0

मुझे खुशी है कि आपको यह दृष्टिकोण उपयोगी लगता है! –

+0

असीमित रूप से growinh शब्दकोश के साथ समस्या 'ConditionalWeakTable' का उपयोग कर तय किया जा सकता है। यह एक शब्दकोश है जो दोनों चाबियों को मानों के दायरे से बाहर जाने की इजाजत देता है, जो चीजों को कचरा प्राप्त करने की इजाजत देता है – Steven