2009-12-23 16 views
6

मैंने हाल ही में वीसी ++ 7 से वीसी ++ 9 तक अपना आवेदन पोर्ट किया। अब यह कभी-कभी बाहर निकलने पर दुर्घटनाग्रस्त हो जाता है - रनटाइम वैश्विक वस्तुओं के विनाशकों को बुलाता है और उनमें से एक में प्रवेश उल्लंघन होता है।"गतिशील अतुलनीय विनाशक" में "गतिशील" का क्या अर्थ है?

जब भी मैं पर्यवेक्षक कॉल शीर्ष कार्यों ढेर हैं:

CMyClass::~CMyClass() <- crashes here 
dynamic atexit destructor for 'ObjectName' 
_CRT_INIT() 
some more runtime-related functions follow 

सवाल शब्द "गतिशील" "गतिशील atexit नाशक" में का अर्थ है क्या है? क्या यह मुझे कोई अतिरिक्त जानकारी प्रदान कर सकता है?

उत्तर

7

अपने वास्तविक कोड के बिना सटीक समस्या इंगित करने के लिए, लेकिन शायद आप इसे अपने आप को इस पढ़ने के बाद मिल सकता है मुश्किल:

http://www.gershnik.com/tips/cpp.asp से

(लिंक अब मर चुका है नीचे देखें)

atexit() और गतिशील/साझा पुस्तकालय

सी और सी ++ मानक पुस्तकालयों में कभी-कभी उपयोगी फ़ंक्शन शामिल होता है: atexit()। यह कॉलर को कॉलबैक पंजीकृत करने की अनुमति देता है जिसे एप्लिकेशन (आमतौर पर) बाहर निकलने पर बुलाया जा रहा है। सी ++ में यह उस तंत्र के साथ भी एकीकृत है जो वैश्विक वस्तुओं के विनाशकों को बुलाता है ताकि एटएक्सिट() को दिए गए कॉल से पहले बनाई गई चीजें कॉलबैक से पहले नष्ट हो जाएंगी और इसके विपरीत। यह सब अच्छी तरह से जाना जाना चाहिए और यह पूरी तरह ठीक काम करता है जब तक कि डीएलएल या साझा पुस्तकालय चित्र में प्रवेश न करें।

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

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

अभी तक इतना अच्छा है, सिवाय इसके कि कुछ कार्यान्वयन सादे पुराने अतुलनीय() के लिए एक ही तंत्र को बढ़ाने के लिए "भूल गए" हैं। चूंकि सी ++ मानक गतिशील पुस्तकालयों के बारे में कुछ भी नहीं कहता है, ऐसे कार्यान्वयन तकनीकी रूप से "सही" होते हैं, लेकिन इससे गरीब प्रोग्रामर की मदद नहीं होती है, जो एक कारण या किसी अन्य कारण से डीएलएल में रहने वाले कॉलबैक को पास करने वाले एटएक्सिट() को कॉल करने की आवश्यकता होती है।

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

पोर्टेबल कोड में आपको क्या करना चाहिए? एक समाधान, निश्चित रूप से, atexit() पूरी तरह से बचने के लिए है। आप अपनी कार्यक्षमता की जरूरत है यह निम्नलिखित तरीके

//Code with atexit() 

void callback() 
{ 
    //do something 
} 

... 
atexit(callback); 
... 

//Equivalent code without atexit() 

class callback 
{ 
public: 
    ~callback() 
    { 
     //do something 
    } 

    static void register(); 
private: 
    callback() 
    {} 

    //not implemented 
    callback(const callback &); 
    void operator=(const callback &); 
}; 

void callback::register() 
{ 
    static callback the_instance; 
} 

... 
callback::register(); 
... 

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

यदि आप उपरोक्त सभी टाइपिंग से बचना चाहते हैं तो क्या होगा? आमतौर पर एक रास्ता है और यह एक साधारण चाल पर निर्भर करता है। टूटा अयोग्य() को कॉल करने के बजाय हमें वैश्विक विनाशकों को पंजीकृत करने के लिए सी ++ कंपाइलर जो भी करता है उसे करने की आवश्यकता है। जीसीसी और अन्य कंपाइलर्स के साथ जो तथाकथित इटेनियम एबीआई (गैर इटेनियम प्लेटफार्मों के लिए व्यापक रूप से उपयोग किया जाता है) लागू करता है, जादू की उत्तेजना को __cxa_atexit कहा जाता है। यहां इसका उपयोग कैसे करें। सबसे पहले नीचे दिए गए कोड को कुछ उपयोगिता शीर्षलेख

#if defined(_WIN32) || defined(LINUX) || defined(SOLARIS) 

    #include <stdlib.h> 

    #define SAFE_ATEXIT_ARG 

    inline void safe_atexit(void (*p)(SAFE_ATEXIT_ARG)) 
    { 
     atexit(p); 
    } 

#elif defined(FREEBSD) 

    extern "C" int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle); 
    extern "C" void * __dso_handle;  


    #define SAFE_ATEXIT_ARG void * 

    inline void safe_atexit(void (*p)(SAFE_ATEXIT_ARG)) 
    { 
     __cxa_atexit(p, 0, __dso_handle); 
    } 

#endif 
And then use it as follows 


void callback(SAFE_ATEXIT_ARG) 
{ 
    //do something 
} 

... 
safe_atexit(callback); 
... 

इस प्रकार __cxa_atexit कार्य निम्नानुसार है। यह एक वैश्विक सूची में कॉलबैक को उसी तरह पंजीकृत करता है, जिस तरह से गैर-डीएलएल अवांछित() करता है। हालांकि यह इसके साथ अन्य दो पैरामीटर भी जोड़ता है। दूसरा पैरामीटर सिर्फ चीज़ रखने के लिए अच्छा है। यह कॉलबैक को कुछ संदर्भ पारित करने की अनुमति देता है (जैसे कि कुछ ऑब्जेक्ट्स) और इसलिए एकाधिक क्लीनअप के लिए एकल कॉलबैक का पुन: उपयोग किया जा सकता है। तीसरा पैरामीटर वह है जिसे हम वास्तव में चाहते हैं। यह केवल एक "कुकी" है जो साझा लाइब्रेरी की पहचान करता है जिसे कॉलबैक से जोड़ा जाना चाहिए। जब कोई साझा लाइब्रेरी अनलोड हो जाती है तो इसका क्लीनअप कोड अतुलनीय कॉलबैक सूची को पार करता है और किसी भी कॉलबैक को कॉल (और हटा देता है) जिसमें एक कुकी होती है जो लाइब्रेरी से जुड़े किसी से मेल नहीं खाती है। कुकी का मूल्य क्या होना चाहिए? यह डीएलएल प्रारंभ पता नहीं है और इसकी डोलोपैन() हैंडल नहीं है जैसा कि कोई मान सकता है। इसके बजाए हैंडल को एक विशेष वैश्विक चर __dso_handle में सी ++ रनटाइम द्वारा बनाए रखा जाता है।

सुरक्षित_एटएक्सिट फ़ंक्शन इनलाइन होना चाहिए। इस तरह यह कॉलिंग मॉड्यूल द्वारा जो कुछ भी __dso_handle का उपयोग किया जाता है, वह वही है जो हमें चाहिए।

क्या आप वर्बोज़ और उपरोक्त पोर्टेबल के बजाय इस दृष्टिकोण का उपयोग करना चाहिए? शायद नहीं, हालांकि कौन जानता है कि आपके पास क्या आवश्यकताएं हो सकती हैं। फिर भी, भले ही आप इसका कभी भी उपयोग न करें, यह इस बात से अवगत होने में मदद करता है कि चीजें कैसे काम करती हैं, यही कारण है कि इसे यहां शामिल किया गया है।

+0

क्या इसका मतलब है कि "गतिशील" "गतिशील लोड लाइब्रेरी" से है? – sharptooth

+0

कोई शब्द रन टाइम के दौरान अतुलनीय फ़ंक्शन कॉलबैक के गतिशील पंजीकरण को संदर्भित नहीं करता है, जो संकलन समय में किए गए स्थिर पंजीकरण के विपरीत है। यह डायनामिक लोड लाइब्रेरीज़ के लिए उपयोगी है क्योंकि आप एटएक्सिट सूची से कॉलबैक फ़ंक्शन को हटा सकते हैं यदि कुछ मनमानी बिंदु पर आपका एप्लिकेशन पहले लोड किए गए डीएल को अनलोड करने का निर्णय लेता है, तो उस स्थिति में आप मैन्युअल रूप से किसी भी क्लीनअप कोड को बिना रिले करने की आवश्यकता के कॉल कर सकते हैं ateixt। – Alon

+0

लिंक मर चुका है। आपको प्रासंगिक जानकारी को अपने उत्तर में कॉपी करने पर विचार करना चाहिए। –

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