2011-05-11 21 views
6

सर्वर एप्लिकेशन पर हमारे पास निम्न है: एक कक्षा जिसे जॉबमेनगर कहा जाता है जो सिंगलटन है। एक और वर्ग, शेड्यूलर, जो यह जांचता रहता है कि क्या यह जॉबमेनगर को किसी भी तरह की नौकरी जोड़ने का समय है। एक ही समय मेंडेडलॉक डेल्फी स्पष्टीकरण/समाधान

TJobManager.Singleton.NewJobItem(parameterlist goes here...); 

, क्लाइंट अनुप्रयोग पर, उपयोगकर्ता कुछ है कि सर्वर के लिए एक ऐसा कॉल करें:

जब यह ऐसा करने के लिए समय है, समयबद्धक की तरह कुछ है। आंतरिक रूप से, सर्वर स्वयं को एक संदेश भेजता है, और उस संदेश को सुनने वाले वर्गों में से एक जॉबमेनगर है। JobManager संदेश संभालती है, और जानता है कि यह सूची में एक नया काम को जोड़ने के लिए, अपने स्वयं के विधि बुला समय आ गया है:

CS.Acquire; 
    try 
    DoSomething; 
    CallAMethodWithAnotherCriticalSessionInternally; 
    finally 
    CS.Release; 
    end; 
:

NewJobItem(parameter list...); 

NewJobItem विधि पर, मैं कुछ इस तरह है

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

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

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

कुछ अधिक जानकारी

मैं जोड़ने के लिए है कि चाहते हैं (यह मूर्खतापूर्ण हो सकता है लेकिन वैसे भी ...) DoSomething अंदर एक और

CS.Acquire; 
    try 
    Do other stuff... 
    finally 
    CS.Release; 
    end; 

यह आंतरिक CS.Release कर रहा है बाहरी सीएस के लिए कुछ भी। पूछताछ? यदि ऐसा है, तो यह वह बिंदु हो सकता है जहां शेड्यूलर गंभीर अनुभाग में प्रवेश कर रहा है, और सभी लॉक और अनलॉक गड़बड़ हो जाता है।

+0

एक गंभीर खंड का उद्देश्य कोड की रक्षा करना है जिसे अलग-अलग धागे पर एक ही समय में निष्पादित नहीं किया जा सकता है, इसलिए यह ठीक है और अच्छा है यदि एक ही उदाहरण पर एक महत्वपूर्ण खंड दो बार (या अधिक) तक पहुंच जाता है क्योंकि इसका मतलब है महत्वपूर्ण अनुभाग यह काम कर रहा है और इसके लिए डिजाइन किया गया है! बुरी बात यह है कि जब सीएस 1 रिलीज नहीं होता है क्योंकि यह थ्रेड प्राप्त कर रहा है तो सीएस 2 हासिल करने का इंतजार कर रहा है, जबकि सीएस 2 रिलीज नहीं होता है क्योंकि यह थ्रेड प्राप्त कर रहा है सीएस 1 (डेडलॉक कहा जाता है) हासिल करने का इंतजार कर रहा है। आप जो कहते हैं उससे, मुझे यकीन नहीं है कि आप डेडलॉक का अनुभव कर रहे हैं ... आप निश्चित क्यों हैं? – jachguate

+0

संदेश हैंडलर विधि के बाद, डीबगिंग करते समय, मैंने महत्वपूर्ण अनुभाग में प्रवेश किया, और सीएस.एक्वायर लाइन पर मेरा ब्रेक पॉइंट, फिर से पहुंचा, शेड्यूलर से आ रहा था - एफ 8 को फिर से मार रहा था, सिस्टम बंद हो गया। – ronaldosantana

+5

आप विंडोज़ संदेश हैंडलिंग लूप पर भी डेडलॉक कर सकते हैं।जब थ्रेडए को सीएस 1 पर लॉक था और फिर एक कॉल करता है जिसके लिए संदेश लूप को लूप की आवश्यकता होती है; और थ्रेड बी प्रभावी रूप से सीएस 1 प्राप्त करने के इंतजार के दौरान संदेश लूप को रोकना, बाधित करना, या अनिश्चित काल में देरी कर रहा है ... –

उत्तर

2

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

आपके प्रश्न के लिए यदि आपका न्यूजोबइटम सी.एक्वायर और डूसमिंग सीएस.एक्वायर एक दूसरे के साथ बातचीत करता है: यह निर्भर करता है। यदि दोनों विधियों में उपयोग की जाने वाली लॉक ऑब्जेक्ट अलग है, तो दो कॉल स्वतंत्र नहीं होनी चाहिए। यदि यह वही वस्तु है तो यह लॉक के प्रकार पर निर्भर करता है। यदि आप ताले फिर से प्रवेश करने वाले ताले हैं (उदाहरण के लिए। वे एक ही धागे से कई बार बुलाए जाने की अनुमति देते हैं और गिनते हैं कि उन्हें कितनी बार अधिग्रहण और रिहा किया गया है) तो यह कोई समस्या नहीं होनी चाहिए। दूसरी तरफ यदि आपके पास सरल लॉक ऑब्जेक्ट्स हैं जो पुनः प्रविष्टि का समर्थन नहीं करते हैं, तो DoSomething CS.release उस थ्रेड के लिए अपना लॉक जारी कर सकता है और फिर CallAMethodWithAnotherCriticalSessionInternally CS CS लॉक की सुरक्षा के बिना चल रहा होगा जो अधिग्रहित किया गया था NewJobItem।

डेडलॉक्स तब होते हैं जब दो या दो से अधिक धागे चलते हैं और प्रत्येक धागा किसी अन्य धागे की प्रतीक्षा कर रहा है ताकि वह अपने स्वयं के काम को जारी रख सकें।

उदाहरण के लिए:

Thread 1 executes: 

lock_a.acquire() 
lock_b.acquire() 
lock_b.release() 
lock_a.release() 


Thread 2 executes: 

lock_b.acquire() 
lock_a.acquire() 
lock_a.release() 
lock_b.release() 

सूचना है कि धागा 2 में ताले धागा 1. अब से विपरीत क्रम में अधिग्रहण कर रहे हैं, तो धागा 1 lock_a प्राप्त कर लेता है और फिर बाधित है और धागा 2 अब चलाता है और lock_b का अधिग्रहण और फिर जारी रखने से पहले लॉक_ए उपलब्ध होने की प्रतीक्षा करना शुरू कर देता है। फिर थ्रेड 1 चल रहा है और अगली चीज़ यह करता है कि यह लॉक_बी हासिल करने का प्रयास करें, लेकिन यह पहले से ही थ्रेड 2 द्वारा लिया गया है और इसलिए यह इंतजार कर रहा है। अंत में हम ऐसी परिस्थिति में हैं जिसमें थ्रेड 1 लॉक_बी को रिलीज़ करने के लिए थ्रेड 2 की प्रतीक्षा कर रहा है और थ्रेड 2 लॉक_ए को रिलीज़ करने के लिए थ्रेड 1 की प्रतीक्षा कर रहा है।

यह एक डेडलॉक है।

कई आम समाधान कर रहे हैं:

  1. केवल अपने सभी कोड में एक साझा वैश्विक लॉक का उपयोग। इस तरह दो धागे के लिए दो धागे इंतजार करना असंभव है। यह लॉक उपलब्ध होने के लिए आपका कोड बहुत इंतजार करता है।
  2. केवल एक बार में आपके कोड को एक लॉक रखने की अनुमति दें। आमतौर पर इसे नियंत्रित करने में बहुत मुश्किल होती है क्योंकि आप विधि कॉल के व्यवहार को नहीं जानते या नियंत्रित नहीं कर सकते हैं।
  3. केवल एक ही समय में अपने कोड को एकाधिक लॉक प्राप्त करने की अनुमति दें, और उन्हें एक ही समय में रिलीज़ करें, और नए लॉक प्राप्त करने की अनुमति न दें, जबकि आपके पास पहले से ही ताले हैं।
  4. सुनिश्चित करें कि सभी ताले एक ही वैश्विक क्रम में अधिग्रहित किए गए हैं। यह एक और आम तकनीक है।

समाधान के साथ 4. आपको सावधान प्रोग्रामिंग की आवश्यकता है और हमेशा यह सुनिश्चित करें कि आप उसी क्रम में ताले/महत्वपूर्ण अनुभाग प्राप्त करें। डिबगिंग में मदद के लिए आप अपने सिस्टम में सभी ताले पर एक वैश्विक ऑर्डर दे सकते हैं (उदाहरण के लिए, प्रत्येक लॉक के लिए सिर्फ एक अद्वितीय पूर्णांक) और फिर यदि आप लॉक प्राप्त करने का प्रयास करते हैं तो एक त्रुटि फेंकती है जिसमें कम रैंकिंग होती है वर्तमान धागा पहले से ही अधिग्रहण कर चुका है (उदाहरण के लिए यदि new_lock.id < lock_already_acquired.id तो अपवाद फेंक दें)

यदि आप वैश्विक डिबगिंग सहायता में नहीं डाल सकते हैं तो यह पता लगाने के लिए कि कौन से ताले ऑर्डर से बाहर किए गए हैं, मैं ' डी सुझाव देता है कि आपको अपने कोड में सभी जगहें मिलती हैं जिन्हें आप लॉक प्राप्त करते हैं और वर्तमान समय के साथ एक डिबगिंग संदेश प्रिंट करते हैं, विधि प्राप्त करने/रिलीज करने की विधि, थ्रेड आईडी और लॉक आईडी प्राप्त की जा रही है। सभी रिलीज कॉल के साथ भी वही काम करें। फिर अपने सिस्टम को तब तक चलाएं जब तक कि आप डेडलॉक प्राप्त न करें और अपनी लॉग फ़ाइल में खोजें जो ताले को किस धागे और किस क्रम में अधिग्रहित किया गया है। फिर तय करें कि कौन सा धागा गलत क्रम में अपने ताले तक पहुंच रहा है और इसे बदल रहा है।

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