2016-10-21 13 views
13

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

+0

ReSharper स्थितियों में, जहां एक सदस्य चर कभी कभी बाहर एक ताला अंदर कभी कभी प्रयोग किया जाता है पाता है डेडलॉक का पता लगाने पर एक दिलचस्प पढ़ा है। –

+0

@ बर्नार्ड हिलर, इस क्षेत्र में रिशेर्पर की क्षमताओं बहुत सीमित हैं। यह स्थिर विश्लेषण पर आधारित है जो मामलों के केवल सीमित सबसेट को पकड़ता है। – user626528

+0

आप नियमित रूप से "लॉक (ऑब्जेक्ट)" कथन का उपयोग करके किसी भी संशोधन के बिना ऐसा करने में सक्षम होना चाहते हैं? मैं कल्पना कर सकता हूं कि आप कुछ ऑब्जेक्ट रैपर का उपयोग करके ऐसा कर सकते हैं जो डीबग मोड में आपको आवश्यक जानकारी प्रदान करेगा। – Evk

उत्तर

1

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

यह कुछ तरीकों से किया जा सकता है और मैं आपको दो का उदाहरण दूंगा। पहला मैन्युअल रूप से है (यह बहुत अच्छा नहीं है लेकिन छोटे कैस के लिए बहुत आसानी से किया जा सकता है)।

मान लीजिए कि आपके पास कक्षा है, दो विधियों के साथ द्वार और अन्य। आपको लगता है कि से विरासत और

public class Doer 
{ 
    public virtual void Do() 
    { 
     //do stuff. 
    } 

    public virtual void Other() 
    { 
     //do stuff. 
    } 
} 

public class AspectDoer : Doer 
{ 
    public override void Do() 
    { 
     LogCall("Do"); 
     base.Do(); 
    } 

    public override void Other() 
    { 
     LogCall("Other"); 
     base.Other(); 
    } 

    private void LogCall(string method) 
    { 
     //Record call 
    } 
} 

यह महान यदि आप केवल एक वर्ग में परवाह है लेकिन जल्दी अव्यावहारिक हो जाता है कि आप कई कक्षाओं के लिए यह करने के लिए है, तो कर सकते हैं। उन मामलों के लिए मैं CastleProxy लाइब्रेरी की तरह कुछ उपयोग करने की सिफारिश करता हूं। यह एक पुस्तकालय है जो गतिशील रूप से किसी भी वर्ग को लपेटने के लिए प्रॉक्सी बनाता है। एक आईओसी के संयोजन में आप आसानी से अपने आवेदन में हर सेवा लपेट सकते हैं।

यहाँ CastleProxy का उपयोग कर, IInterceptors में मुख्य बिंदुओं जा रहा है उपयोग ProxyGenerator.GenerateProxy और पारित प्रणाली को बुलाती है चारों ओर सामान करने के लिए की एक त्वरित उदाहरण है:

[Test] 
    public void TestProxy() 
    { 
     var generator = new ProxyGenerator(); 
     var proxy = generator.CreateClassProxy<Doer>(new LogInterceptor()); 
     proxy.Do(); 
     Assert.True(_wasCalled); 
    } 

    private static bool _wasCalled = false; 
    public class LogInterceptor : IInterceptor 
    { 
     public void Intercept(IInvocation invocation) 
     { 
      Log(invocation.Method.Name); 
      invocation.Proceed(); 
     } 

     private void Log(string name) 
     { 
      _wasCalled = true; 
     } 
    } 

अब, लॉगिंग भाग। मुझे यकीन नहीं है कि आपको वास्तव में लॉकलेस होने की आवश्यकता है, छोटे ताले पर्याप्त हो सकते हैं लेकिन आप सोचने की सोचते हैं।

मुझे सी # में कई टूल्स नहीं पता हैं जो लॉक फ्री ऑपरेशंस का समर्थन करते हैं लेकिन इसका सबसे सरल संस्करण मैं देख सकता हूं कि किसी भी समय विधि में कितने उदाहरण हैं, इसका काउंटर बढ़ाने के लिए इंटरलाक्ड का उपयोग करना है। कुछ इस तरह दिखाई:

 [Test] 
    public void TestProxy() 
    { 
     var generator = new ProxyGenerator(); 
     var proxy = generator.CreateClassProxy<Doer>(new LogInterceptor()); 
     proxy.Do(); 
     Assert.AreEqual(1, _totalDoCount); 
    } 

    private static int _currentDoCount = 0; 
    private static int _totalDoCount = 0; 
    public class LogInterceptor : IInterceptor 
    { 
     public void Intercept(IInvocation invocation) 
     { 
      if (invocation.Method.Name == "Do") 
      { 
       var result = Interlocked.Increment(ref _currentDoCount); 
       Interlocked.Increment(ref _totalDoCount); 
       if(result > 1) throw new Exception("thread safe violation"); 
      } 


      invocation.Proceed(); 
      Interlocked.Decrement(ref _currentDoCount); 
     } 
    } 

Interlocked धागा सुरक्षित संचालन करने के लिए जादुई रजिस्टर जादू का उपयोग करता है (तुलना करें-और-स्वैप मुझे विश्वास है, लेकिन मैं वास्तव में नहीं पता है)। यदि आपको "यह हुआ" की तुलना में अधिक संदर्भ की आवश्यकता है। आप एक समवर्ती स्टैक या एक समवर्ती कतार का उपयोग कर सकते हैं जो लॉकलेस हैं (वे इंटरलॉक का भी उपयोग करते हैं: https://msdn.microsoft.com/en-us/library/dd997305.aspx/)। हालांकि, इन पर एक टाइमस्टैम्प शामिल होगा, क्योंकि मैंने उन्हें यह जानने के लिए पर्याप्त उपयोग नहीं किया है कि क्या वे घटित होने के क्रम में तत्वों को वापस करने का वादा करते हैं।

जैसा कि मैंने उपरोक्त कहा है, आपको लॉक फ्री ऑपरेशंस की आवश्यकता नहीं है लेकिन यह चाहिए। मुझे नहीं पता कि इनमें से कोई भी आपके लिए एकदम सही फिट है क्योंकि मुझे आपकी सटीक समस्या नहीं है, लेकिन इससे आपको इससे निपटने के लिए कुछ टूल उपलब्ध कराए जाएंगे।

+0

हां, 'इंटरलाक्ड.इंटरमेंट' परमाणु तुलना-और-स्वैप ऑपरेशन का उपयोग करता है। – Georg

0

आप host the CLR yourself कर सकते हैं, और IHostSyncManager::CreateMonitorEvent विधि का उपयोग करके किए गए ताले को ट्रैक कर सकते हैं। इसके बाद आपको अपने मेजबान से अपने स्वयं के तंत्र को "IsLockTaken()" नामक विधि में बेनकाब करने की आवश्यकता होगी। फिर आप इसे अपने वास्तविक कोड में अपनी विधि से कॉल कर सकते हैं।

मुझे लगता है कि यह संभव है, लेकिन यह काफी काम होगा और लगभग निश्चित रूप से उस समस्या से पूरी तरह से व्याकुलता है जिसे आप हल करने की कोशिश कर रहे हैं, लेकिन इसमें कोई संदेह नहीं है!

यहाँ https://blogs.msdn.microsoft.com/sqlclr/2006/07/25/deadlock-detection-in-sql-clr/

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