2012-08-02 12 views
34

क्यों यह एक बुरा व्यवहार निम्न कोड में के रूप में लॉक का उपयोग करने के लिए है, मैं इस में this SO question hereउस ऑब्जेक्ट को लॉक करने का एक बुरा अभ्यास क्यों है जिसे हम बदलने जा रहे हैं?

private void DoSomethingUseLess() 
{ 
    List<IProduct> otherProductList = new List<IProduct>(); 
    Parallel.ForEach(myOriginalProductList, product => 
     { 
      //Some code here removed for brevity 
      //Some more code here :) 
      lock (otherProductList) 
      { 
       otherProductList.Add((IProduct)product.Clone()); 
      } 
     }); 
} 

there से अधिक जवाब उत्तरों के आधार पर एक बुरी बात है यह सोचते कर रहा हूँ का उल्लेख है, यह बुरा व्यवहार है कि लेकिन वे कहते हैं कि क्यों नहीं

नोट: कृपया कोड की उपयोगिता पर ध्यान न दें, यह सिर्फ उदाहरण प्रयोजन के लिए है और मैं इसे बिल्कुल उपयोगी

+2

आपके पास कोड के साथ, 'अन्य उत्पाद सूची' इस कोड के लिए स्थानीय है, इसलिए इसे लॉक करने में कोई समस्या नहीं होगी (क्योंकि कोई भी इसे देख सकता है)। समस्याएं केवल (संभावित रूप से) आती हैं जब आप किसी अन्य चीज़ को लॉक करते हैं जो 'अन्य कोड' भी देख सकता है। – AakashM

+0

@AakashM: सच नहीं है। यह कोड जितना अधिक नाजुक होना चाहिए, और आप यह गारंटी नहीं दे सकते कि 'अन्य उत्पाद सूची' फ़ंक्शन के बाहर या कक्षा के बाहर भी नहीं पारित की गई है। यदि "ब्रेवटी के लिए कोड हटा दिया गया है" में 'SomeRandomClass.SomeMethod (अन्य उत्पाद सूची)' पर कॉल शामिल है, तो आपने ऑब्जेक्ट को किसी और को दिया है। –

+1

@DanPuzey इसलिए मेरी चेतावनी 'कोड के साथ आपके पास है'। मैं * गारंटी दे सकता हूं, क्योंकि मैं पूरे दायरे और चर के चर के उपयोग को देख सकता हूं। अगर टिप्पणियों को कोड द्वारा प्रतिस्थापित किया गया था, तो वास्तव में चीजें अलग हो सकती हैं; लेकिन यह हमेशा सच है कि अलग-अलग प्रश्नों के अलग-अलग उत्तर हो सकते हैं ... – AakashM

उत्तर

32

सी # भाषा संदर्भसे नहीं है:

सामान्य रूप से, सार्वजनिक प्रकार, या आपके कोड के नियंत्रण से परे उदाहरणों को लॉक करने से बचें। आम निर्माणों lock (this), lock (typeof (MyType)), और lock ("myLock") इस निर्देश का उल्लंघन:

lock (this) एक समस्या है अगर उदाहरण के सार्वजनिक रूप से पहुँचा जा सकता है।

lock (typeof (MyType)) एक समस्या है यदि MyType सार्वजनिक रूप से सुलभ है।

lock("myLock") एक समस्या है क्योंकि प्रक्रिया में कोई अन्य कोड उसी स्ट्रिंग का उपयोग करके, उसी लॉक को साझा करेगा।

सर्वश्रेष्ठ अभ्यास पर लॉक करने के लिए एक निजी वस्तु को परिभाषित करने के लिए है, या एक निजी स्थिर वस्तु चर सभी उदाहरणों के लिए आम डेटा की रक्षा के लिए।

आपके मामले में, मैं सुझाव है कि संग्रह आप को संशोधित किया जाएगा पर ताला लगा बुरा व्यवहार है जैसा कि ऊपर मार्गदर्शन पढ़ा होगा। उदाहरण के लिए, यदि आपने यह कोड लिखा है:

lock (otherProductList) 
{ 
    otherProductList = new List<IProduct>(); 
} 

... तो आपका लॉक बेकार होगा। इन कारणों से लॉकिंग के लिए समर्पित object चर का उपयोग करने की अनुशंसा की जाती है।

ध्यान दें कि इसका मतलब यह नहीं है कि आपका आवेदन ब्रेक होगा यदि आप पोस्ट किए गए कोड का उपयोग करते हैं। "सर्वोत्तम प्रथाओं" को आमतौर पर आसानी से दोहराए जाने वाले पैटर्न प्रदान करने के लिए परिभाषित किया जाता है जो अधिक तकनीकी रूप से लचीला होते हैं। यही है, यदि आप सर्वोत्तम अभ्यास का पालन करते हैं और एक समर्पित "लॉक ऑब्जेक्ट" रखते हैं, तो आप पर कभी भी लिखने की संभावना नहीं है lock-आधारित कोड लिखें; यदि आप सबसे अच्छे अभ्यास का पालन नहीं करते हैं, तो शायद एक सौ में एक बार, आप आसानी से बचाए गए समस्या से काट लेंगे।

अतिरिक्त (और अधिक आम तौर पर), सर्वोत्तम प्रथाओं का उपयोग करके लिखे गए कोड को आम तौर पर अधिक आसानी से संशोधित किया जाता है, क्योंकि आप अप्रत्याशित दुष्प्रभावों से कम सावधान रह सकते हैं।

+0

तक पहुंचाया जाएगा यह एक अच्छा जवाब है , क्या कोई अन्य परिदृश्य है, जहां इससे कोई समस्या हो सकती है, कृपया जांचें कि मैंने – Vamsi

+4

पर सवाल अपडेट किया है ठीक है आप एमएसडीएन उद्धृत कर रहे हैं, और इसे दोहराते हुए सार्वजनिक रूप से सुलभ वस्तुओं को लॉक करने के लिए बुरी आदत है, लेकिन अभी भी यह नहीं बता रहा है कि क्यों एक बुरा अभ्यास है। जैसे deadlocks के लिए जोखिम (@ केन 2k का जवाब) एक और कारण है। – jeroenh

+1

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

2

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

अपने कोड के आधार पर निम्न उदाहरण कल्पना कीजिए:

namespace ClassLibrary1 
{ 
    public class Foo : IProduct 
    { 
    } 

    public interface IProduct 
    { 
    } 

    public class MyClass 
    { 
     public List<IProduct> myOriginalProductList = new List<IProduct> { new Foo(), new Foo() }; 

     public void Test(Action<IEnumerable<IProduct>> handler) 
     { 
      List<IProduct> otherProductList = new List<IProduct> { new Foo(), new Foo() }; 
      Parallel.ForEach(myOriginalProductList, product => 
      { 
       lock (otherProductList) 
       { 
        if (handler != null) 
        { 
         handler(otherProductList); 
        } 

        otherProductList.Add(product); 
       } 
      }); 
     } 
    } 
} 

अब आप अपने पुस्तकालय संकलन, एक ग्राहक को भेज सकते हैं और इस ग्राहक को अपने कोड में लिखते हैं:

public class Program 
{ 
    private static void Main(string[] args) 
    { 
     new MyClass().Test(z => SomeMethod(z)); 
    } 

    private static void SomeMethod(IEnumerable<IProduct> myReference) 
    { 
     Parallel.ForEach(myReference, item => 
     { 
      lock (myReference) 
      { 
       // Some stuff here 
      } 
     }); 
    } 
} 

तो फिर वहाँ सकता है अपने ग्राहक के लिए एक अच्छा हार्ड-टू-डीबग डेडलॉक बनें, otherProductList इंस्टेंस के लिए अब दो लॉक किए गए थ्रेड का उपयोग नहीं किया जा रहा है।

मैं मानता हूं कि यह परिदृश्य होने की संभावना नहीं है, लेकिन यह दिखाता है कि यदि आपका लॉक संदर्भ उस कोड के टुकड़े में दिखाई देता है जो आपके पास नहीं है, तो किसी भी संभावित तरीके से, तो अंतिम कोड होने की संभावना है टूटा

+0

नहीं, यह संभव नहीं है, आपके कोड 'myOriginalProductList' के अनुसार केवल 'अन्य उत्पाद सूची' के बाहर पहुंच योग्य नहीं है, कृपया – Vamsi

+0

@Vamsiकृष्ण आप सही हैं, मैंने प्रश्न को गलत तरीके से पढ़ा है। मैंने एक संभावित डेडलॉक प्रदर्शित करने के लिए उदाहरण अपडेट किया – ken2k

+0

वाह यह एक अच्छा है, मुझे नहीं पता कि यह हो सकता है, +1 – Vamsi