c++ - थ्रेड ऑब्जेक्ट के लिए WaitForSingleObject DLL अनलोड में काम नहीं करता



multithreading winapi (1)

आप DllMain () में बाहर निकलने के लिए एक थ्रेड का इंतजार नहीं कर सकते। जब तक धागा पहले से ही DLL_PROCESS_DETACH प्राप्त हुआ था, तब तक ऐसा करने से हमेशा गतिरोध लगा होगा। यह अपेक्षित व्यवहार है

इसका कारण यह है कि लोडर लॉक के माध्यम से, DllMain () को कॉल किए गए हैं। जब ExitThread () को बुलाया जाता है, तो वह लोडर ताला का दावा करता है ताकि वह DLL_THREAD_DETACH के साथ DllMain () को कॉल कर सके। उस कॉल के समाप्त होने तक, धागा अभी भी चल रहा है

इसलिए DllMain धागा को बाहर निकलने का इंतजार कर रहा है, और धागा DllMain के बाहर निकलने के लिए इंतजार कर रहा है, एक क्लासिक डेडलॉक स्थिति।

एमएसडीएन पर डायनेमिक-लिंक लाइब्रेरी सर्वश्रेष्ठ अभ्यास भी देखें।

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

मामले में जहां पीछे की संगतता आवश्यकताओं को ऐसे असंभव कार्य को जोड़ना पड़ता है, और अगर आपके पास कार्यकर्ता थ्रेड्स हों, तो अपने डीएलएल को दो हिस्सों में विभाजित करने पर विचार करें, जिनमें से एक गतिशील रूप से दूसरे द्वारा भरी हुई है गतिशील रूप से लोड किए गए भाग में (कम से कम) कार्यकर्ता धागे द्वारा आवश्यक सभी कोड शामिल होंगे।

जब DLL को स्वयं DLL_PROCESS_DETACH प्राप्त होता है, तो आप केवल थ्रेड को संकेत करने के लिए घटना को सेट करते हैं और फिर तुरंत वापस लौटाते हैं थ्रेड्स में से एक को अन्य सभी के लिए इंतजार करने के लिए नामित किया जाना चाहिए और फिर दूसरी DLL को मुक्त करें, जिसे आप FreeLibraryAndExitThread () का सुरक्षित रूप से उपयोग कर सकते हैं।

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

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

यहाँ पकड़ यह है कि कॉलबैक को किसी भी विंडोज़ एपीआई से बचना चाहिए जो लोडर लॉक को ले सकता है। यह दस्तावेज नहीं है कि इस संबंध में कौन सी एपीआई कॉल सुरक्षित हैं, और यह विंडोज के विभिन्न संस्करणों के बीच भिन्न है। यदि आप SetEvent या WriteFile की तुलना में अधिक जटिल बात कर रहे हैं, कहते हैं, या यदि आप स्थानीय Windows एपीआई कार्यों के बजाय एक पुस्तकालय का उपयोग कर रहे हैं, तो आपको इस दृष्टिकोण का उपयोग नहीं करना चाहिए

मैंने विंडोज थ्रेड तंत्र के एक अप्रत्याशित व्यवहार पर ठोकर खाई है जब DLL लोड हो रहा है। ए में कार्यकर्ता थ्रेड ऑब्जेक्ट्स का एक पैकेट है और जब मैं डीएलएल लोड हो रहा है, तो मैं उन्हें विनम्रतापूर्वक खत्म करने की कोशिश कर रहा हूं (DllMain DLL_PROCESS_DETACH के माध्यम से)। कोड बहुत सरल है (मैं थ्रेड का इंतजार लूप समाप्त करने के लिए एक इवेंट भेजता हूं):

WaitForSingleObject( ThrHandle, INFINITE );
CloseHandle( ThrHandle );

अभी तक WaitForSingleObject पूरी बात लटका हुआ है यह ठीक काम करता है अगर मैं DLL लोड होने से पहले इसे करता हूं। यह व्यवहार कैसे तय किया जा सकता है?