2008-09-16 14 views
29

मान लीजिए कि मैं सी ++ में एक DLL लिखते हैं, और एक गैर तुच्छ नाशक के साथ एक कक्षा के एक वैश्विक वस्तु घोषणा करते हैं। डीएलएल अनलोड होने पर विनाशक को बुलाया जाएगा?डीएलएल में घोषित वैश्विक चर के साथ क्या होता है?

उत्तर

33

विंडोज सी ++ डीएलएल में, सभी वैश्विक वस्तुओं (कक्षाओं के स्थिर सदस्यों सहित) का निर्माण डीएलएम_PROCESS_ATTACH के साथ डेलमेन की कॉलिंग से ठीक पहले किया जाएगा, और डीएलएल_PROCESS_DETACH के साथ डेलमेन की कॉल के बाद ही उन्हें नष्ट कर दिया जाएगा।

अब, आप तीन समस्याओं पर विचार करना चाहिए:

0 - बेशक, वैश्विक गैर-स्थिरांक वस्तुओं बुराई कर रहे हैं (लेकिन आप पहले से ही जानते हैं कि, तो मैं mentionning बहु सूत्रण, ताले, देवता-वस्तुओं, आदि से बच सकेंगे ।)

1 - ऑब्जेक्ट्स या विभिन्न संकलन इकाइयों (यानी सीपीपी फाइलों) के निर्माण का आदेश गारंटी नहीं है, इसलिए आप उम्मीद नहीं कर सकते कि ऑब्जेक्ट ए को बी से पहले बनाया जाएगा यदि दो ऑब्जेक्ट्स दो अलग-अलग में दोबारा लगाए गए हैं सीपीपी। यह महत्वपूर्ण है यदि बी ए पर निर्भर करता है। समाधान सभी वैश्विक वस्तुओं को उसी सीपीपी फ़ाइल में स्थानांतरित करना है, जैसा कि एक ही संकलन इकाई के अंदर है, वस्तुओं के अस्थिरता का क्रम निर्माण का आदेश होगा (और आदेश के विपरीत विनाश)

2 - चीजें हैं जो DllMain में क्या करने के लिए मना कर रहे हैं। उन चीजों को भी रचनाकारों में, वर्जित भी किया जाता है। तो कुछ लॉक करने से बचें। इस विषय पर रेमंड चेन के उत्कृष्ट ब्लॉग देखें:

http://blogs.msdn.com/oldnewthing/archive/2004/01/27/63401.aspx

http://blogs.msdn.com/oldnewthing/archive/2004/01/28/63880.aspx

इस मामले में, आलसी आरंभीकरण दिलचस्प हो सकता है: कक्षाएं एक "गैर-प्रारंभ" राज्य में रहते हैं (आंतरिक संकेत शून्य कर रहे हैं, बुलियन झूठे हैं, जो भी हो) जब तक कि आप उनकी विधियों में से किसी एक को कॉल न करें, उस बिंदु पर वे स्वयं को प्रारंभ करेंगे। यदि आप उन वस्तुओं को मुख्य (या मुख्य के वंशज कार्यों में से एक) के अंदर उपयोग करते हैं, तो आप ठीक रहेंगे क्योंकि उन्हें DllMain के निष्पादन के बाद बुलाया जाएगा।

3 - बेशक, यदि डीएलएल ए में कुछ वैश्विक वस्तुएं डीएलएल बी में वैश्विक वस्तुओं पर निर्भर करती हैं, तो आपको डीएलएल लोडिंग ऑर्डर और इस प्रकार निर्भरता के बारे में बहुत सावधान रहना चाहिए।इस मामले में, प्रत्यक्ष या अप्रत्यक्ष परिपत्र निर्भरताओं वाले डीएलएल आपको सिरदर्द की पागल राशि का कारण बनेंगे। सर्कुलर निर्भरता तोड़ने का सबसे अच्छा समाधान है।

पीएस .: ध्यान दें कि सी ++ में, कन्स्ट्रक्टर फेंक सकता है, और आप डीएलएल लोडिंग के बीच में अपवाद नहीं चाहते हैं, इसलिए सुनिश्चित करें कि आपकी वैश्विक वस्तुएं बहुत अच्छे कारण के बिना अपवाद का उपयोग नहीं कर रही हैं। चूंकि सही ढंग से लिखित विनाशकों को फेंकने के लिए अधिकृत नहीं है, इस मामले में डीएलएल अनलोडिंग ठीक होनी चाहिए।

+2

तो है, है एक और प्रक्रिया में मनाया परिवर्तन? –

+2

@ एलबी--: आमतौर पर, नहीं: प्रत्येक प्रक्रिया का अपना वैश्विक चर होता है * जब तक कि आप उन्हें साझा मेमोरी में मैप करने के लिए न हों, या उस डीएलएल का उपयोग करके सभी प्रक्रियाओं के बीच साझा करने के लिए ओएस विशिष्ट चाल का उपयोग करें (मैं नहीं करता विंडोज़ पर बिल्कुल चाल याद रखें, लेकिन इसमें #pragma घोषणाएं शामिल हैं, आईआईआरसी) – paercebal

3

यह कहा जाना चाहिए जब या तो आवेदन समाप्त हो जाती है या DLL उतार दिया जाता है, जो भी पहले हो। ध्यान दें कि यह वास्तविक रनटाइम पर कुछ हद तक निर्भर है जिसके खिलाफ आप संकलन कर रहे हैं।

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

1

जब DllMain fdwReason = DLL_PROCESS_DETACH पैरामीटर के साथ यह कहा जाता है का मतलब है DLL आवेदन के द्वारा उतार दिया है। वैश्विक/स्थैतिक वस्तुओं के विनाशक के नाम से पहले यह समय है।

4

आप वास्तविक कोड जब एक .dll जोड़ने निष्पादित हो जाता है कि देखने के लिए चाहते हैं, %ProgramFiles%\Visual Studio 8\vc\crt\src\dllcrt0.c पर एक नज़र डालें।

निरीक्षण से, विनाशकों को _cexit() के माध्यम से बुलाया जाएगा जब डीएलआर सीआरटी द्वारा बनाए गए आंतरिक संदर्भ गणना शून्य हिट होगी।

1

एक्सटेंशन में * .exe, * .dll के साथ बाइनरी छवि फ़ाइलों में PE format ऐसी फ़ाइलों में एंट्री पॉइंट है। या जैसे * CRTStartup कुछ आप की तरह

DUMPBIN DUMPBIN उपकरण के साथ इसे देख सकते हैं/हेडर dllname.dll

आप Microsoft से सी क्रम का उपयोग करते हैं, तो अपने प्रवेश बिंदु हो जाएगा * DllMainCRTStartup

ऐसे कार्य क्रमशः सी और सी ++ रनटाइम प्रारंभ करते हैं और क्रमशः (मुख्य, विनमेन) या डीएलएममेन को निष्पादन करते हैं।

आप माइक्रोसॉफ्ट के कुलपति संकलक का उपयोग करते हैं तो आप तुम्हारा कुलपति निर्देशिका में इस कार्य के स्रोत कोड को देख सकते हैं:

  • crt0.c
  • dllcrt0.c

DllMainCRTStartup प्रक्रिया सब बातों सामान्य परिदृश्य में .data अनुभागों से अपने वैश्विक चर को init/deinit करने की आवश्यकता है, जब यह dll unload के दौरान अधिसूचना DLL_PROCESS_DETACH को पुनर्प्राप्त करता है। उदाहरण के लिए:

  • मुख्य या कार्यक्रम रिटर्न के स्टार्टअप धागे की WinMain प्रवाह को नियंत्रित
  • आप explictly FreeLibrary फोन और प्रयोग-dll-काउंटर एक प्रक्रिया एक वैश्विक मूल्य में परिवर्तन शून्य
संबंधित मुद्दे