2011-01-30 5 views
20

मैंने एक परीक्षण लिखा है जो मुझे लगता है कि डेडलॉक के लिए एक वैध मामला होना चाहिए। ऐसा प्रतीत होता है कि एक बार lock को कक्षा के एक उदाहरण से अधिग्रहित किया गया है, तो उस उदाहरण को lock को फिर से हासिल करने की आवश्यकता नहीं है, भले ही मैं स्पष्ट रूप से lock को दूसरी विधि को कॉल करने का प्रयास करता हूं।ब्लॉक को लॉक करने के लिए लॉक किए गए और आगे के प्रयासों को लॉक करें: क्या सी # लॉक फिर से प्रवेश कर रहे हैं?

यहाँ वर्ग है:

internal class Tester 
{ 
    private readonly object _sync = new object(); 

    public Tester() { } 

    public void TestLock() 
    { 
     lock (_sync) 
     { 
      for (int i = 0; i < 10; i++) 
      { 
       Deadlock(i); 
      } 
     } 

    } 

    private void Deadlock(int i) 
    { 
     lock (_sync) 
     { 
      Trace.WriteLine(i + " no deadlock!"); 
     } 
    } 
} 

आउटपुट:

0 कोई गतिरोध!
1 कोई डेडलॉक नहीं!
2 कोई डेडलॉक नहीं!
3 कोई डेडलॉक नहीं!
4 कोई डेडलॉक नहीं!
5 कोई डेडलॉक नहीं!
6 कोई डेडलॉक नहीं!
7 कोई डेडलॉक नहीं!
8 कोई डेडलॉक नहीं!
9 कोई डेडलॉक नहीं!

मैंने सोचा होगा कि इससे डेडलॉक होगा ... क्या कोई इस पर कुछ प्रकाश डाल सकता है?

उत्तर

41

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

1

आपके परिदृश्य में, आपके पास एक और लॉक के भीतर लॉक है। एक बार जब कोड "डेडलॉक" में नेस्टेड लॉक को हिट करता है, तो "लॉक (...)" कोड अनिवार्य रूप से अनदेखा कर दिया जाता है क्योंकि यह इसे पहले से ही "टेस्ट लॉक" में अधिग्रहित कर चुका है।

थ्रेडिंग के लिए महान स्रोत: http://www.albahari.com/threading/part2.aspx

+1

मैं मल्टीथ्रेडिंग के साथ बहुत सहज हूं, लेकिन मुझे लगता है कि मुझे कभी एहसास नहीं हुआ कि सी # ताले फिर से प्रवेश कर रहे हैं। उत्तर के लिए धन्यवाद ... – Kiril

13

मॉनीटर, म्यूटेक्स और रीडरवाइटर लॉक क्लासेस ताले बनाए रखने वाले ताले बनाए रखते हैं। रीडरवाइटर लॉकस्लिम क्लास आपको चुनने देता है, इसमें एक कन्स्ट्रक्टर है जो लॉक रेकर्सियन पॉलिसी मान लेता है। LockRecursionPolicy.NRecursion का उपयोग करना एक अनुकूलन है, यदि आपका लॉकिंग वास्तव में ठीक है तो एक काफी बड़ा है।

सेमफोर क्लास एक सिंक्रनाइज़ेशन क्लास है जिसमें कोई थ्रेड एफ़िनिटी नहीं है। इस कोड को मज़बूती से गतिरोध:

class Tester { 
    private Semaphore sem = new Semaphore(1, 1); 
    public void TestLock() { 
     sem.WaitOne(); 
     for (int i = 0; i < 10; i++) Deadlock(i); 
     sem.Release(); 
    } 

    private void Deadlock(int i) { 
     if (!sem.WaitOne(100)) Console.WriteLine("deadlock!"); 
     else { 
      sem.Release(); 
      Console.WriteLine("No deadlock!"); 
     } 
    } 
} 

सामान्य में, धागा affine तुल्यकालन कक्षाएं गतिरोध को दो धागे और दो ताले की आवश्यकता है। मानक पैटर्न एक थ्रेड के लिए ताले ए और बी हासिल करने के लिए है, दूसरे के लिए बी और ए प्राप्त करने के लिए आदेश महत्वपूर्ण है।

.NET प्रोग्रामिंग में चारों ओर कम स्पष्ट डेडलॉक्स परिदृश्य हैं, जो ताले से प्रेरित हैं जिन्हें आप नहीं देख सकते क्योंकि वे .NET Framework कोड में अंतर्निहित हैं। पृष्ठभूमि वर्कर के लिए एक बहुत ही क्लासिक है। आप UI थ्रेड में कोड लिख सकते हैं जो व्यस्त संपत्ति पर स्पिन करता है, बीजीडब्ल्यू को पूरा करने की प्रतीक्षा करता है। यह हमेशा deadlocks जब बीजीडब्ल्यू एक RunWorker पूर्ण घटना हैंडलर है। यह तब तक नहीं चल सकता जब तक यूआई थ्रेड निष्क्रिय न हो जाए, बीजीडब्ल्यू की व्यस्त संपत्ति तब तक गलत नहीं होगी जब तक ईवेंट हैंडलर समाप्त नहीं हो जाता।

+0

महान जानकारी के लिए धन्यवाद! – Kiril