2009-12-26 16 views
6

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

सी # और पायथन में, जब एक अनचाहे अपवाद होता है, तो उपयोगकर्ता को एक अच्छा स्टैक ट्रेस मिलता है और आम तौर पर बहुत उपयोगी अनमोल डिबगिंग जानकारी। यदि आप ओएसएस आवेदन पर काम कर रहे हैं, तो उपयोगकर्ताओं को उस जानकारी को समस्या रिपोर्ट में पेस्ट करना है ... अच्छी तरह से बस कहना है कि मुझे इसके बिना जीना मुश्किल लगता है। इस सी ++ प्रोजेक्ट के लिए, मुझे "एप्लिकेशन क्रैश हो गया", या अधिक सूचित उपयोगकर्ताओं से, "मैंने एक्स, वाई और जेड किया, और फिर यह क्रैश हो गया"। लेकिन मैं भी उस डिबगिंग जानकारी चाहता हूँ!

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

और अब मैं चाहता हूं कि मेरे अनचाहे अपवादों के लिए। मैं boost::exception का उपयोग कर रहा हूं, और उनके पास यह बहुत अच्छा diagnostic_information चीज़माजिग है जो कि (असम्बद्ध) फ़ंक्शन नाम, फ़ाइल, रेखा और सबसे महत्वपूर्ण रूप से अन्य अपवाद विशिष्ट जानकारी प्रोग्रामर को उस अपवाद में जोड़ा जा सकता है।

स्वाभाविक रूप से, जब भी मैं कर सकता हूं, मैं कोड के अंदर अपवादों को संभालेगा, लेकिन मैं यह सोचने के लिए मूर्ख नहीं हूं कि मैं एक जोड़े को (अनजाने में, निश्चित रूप से) छोड़ने नहीं दूँगा।

तो मैं अपने मुख्य प्रवेश बिंदु को try ब्लॉक के अंदर catch के साथ लपेटना चाहता हूं जो एक विशेष संवाद बनाता है जो उपयोगकर्ता को सूचित करता है कि एप्लिकेशन में कोई त्रुटि आई है, उपयोगकर्ता द्वारा क्लिक किए जाने पर अधिक विस्तृत जानकारी प्रस्तुत की जाती है "अधिक" या "डीबग जानकारी" या जो भी हो। इसमें डायग्नोस्टिक_इनॉर्मेशन से स्ट्रिंग होगी। इसके बाद मैं उपयोगकर्ताओं को इस जानकारी को समस्या रिपोर्ट में पेस्ट करने का निर्देश दे सकता था।

लेकिन एक नाराज आंत महसूस मुझे बता रहा है कि कोशिश ब्लॉक में सब कुछ लपेटना वास्तव में एक बुरा विचार है। क्या मैं बेवकूफ करने वाला हूँ? यदि यह है (और यदि यह नहीं है), जो मैं चाहता हूं उसे प्राप्त करने का एक बेहतर तरीका क्या है?

उत्तर

3

अपने सभी कोड को एक try/catch ब्लॉक में लपेटना ठीक है। उदाहरण के लिए, यह इसके अंदर किसी भी चीज़ के निष्पादन को धीमा नहीं करेगा। असल में, मेरे सभी कार्यक्रमों में इस फ्रेमवर्क के समान (कोड समान है):

int execute(int pArgc, char *pArgv[]) 
{ 
    // do stuff 
} 

int main(int pArgc, char *pArgv[]) 
{ 
    // maybe setup some debug stuff, 
    // like splitting cerr to log.txt 

    try 
    { 
     return execute(pArgc, pArgv); 
    } 
    catch (const std::exception& e) 
    { 
     std::cerr << "Unhandled exception:\n" << e.what() << std::endl; 
     // or other methods of displaying an error 

     return EXIT_FAILURE; 
    } 
    catch (...) 
    { 
     std::cerr << "Unknown exception!" << std::endl; 

     return EXIT_FAILURE; 
    } 
} 
+0

+1, लेकिन क्या यह 'std :: अपवाद 'अपवाद से प्राप्त कुछ को कॉल करने के लिए सही है? ;-) (और नहीं, मेरे पास फेंकने वाले int या कुछ समान रूप से तेज किनारे के लिए बेहतर नाम नहीं है)। –

+0

आपका मतलब है 'पकड़ो (...) '? मेरे पास केवल पूर्णता के लिए है, अगर वास्तव में कुछ भी इसमें प्रवेश करता है तो मैं आश्चर्यचकित हूं और याद रखता हूं कि कौन यादृच्छिक सामान फेंक रहा है। – GManNickG

+0

जीएमएन, हाँ, मैं आपका इरादा देखता हूं, यह सिर्फ इतना है कि मुझे आश्चर्य है कि अगर कोई इस मामले में "अज्ञात अपवाद" या "अज्ञात कुछ हमारे रास्ते को फेंक दिया" कहता है ;-) शब्दावली का मामला। –

1

नहीं यह बेवकूफ नहीं है। यह एक बहुत अच्छा विचार है, और जब तक आप एक अनचाहे अपवाद नहीं करते हैं, तब तक इसे रनटाइम पर लगभग कुछ भी नहीं लगता है।

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

मैं रजिस्टरों, ऐप संस्करण और बिल्ड नंबर, अपवाद प्रकार और हेक्स मानों के लिए ऑफसेट्स के साथ हेक्स में एक स्टैक डंप शामिल करता हूं जो कोड के पते हो सकता है। संस्करण संख्या शामिल करना और अपने exe की संख्या/दिनांक बनाना सुनिश्चित करें।

आप स्टैक मानों को "मॉड्यूलनाम + ऑफसेट" में आसानी से बदलने के लिए VirtualQuery का भी उपयोग कर सकते हैं। और, एमएपी फ़ाइल के साथ संयुक्त अक्सर आपको बताएगा कि आप कहां दुर्घटनाग्रस्त हो गए हैं।

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

यदि आप 'त्रुटि रिपोर्ट रिपोर्ट' बटन रखने की परेशानी पर जाना चाहते हैं तो भी बेहतर होगा, लेकिन उपयोगकर्ताओं को अपने ईमेल में टेक्स्ट प्राप्त करने का एक तरीका देने से आपको सबसे अधिक रास्ता मिल जाता है, और नहीं "मैं उनके साथ कौन सी जानकारी साझा कर रहा हूं" के बारे में कोई लाल झंडे उठाओ?

+0

आपके द्वारा वर्णित वर्चुअलQuery क्या है? इसके बारे में कभी नहीं सुना, लेकिन यह हमारे एसपीएआरसी मंच के लिए दिलचस्प हो सकता है। –

+0

यह एक Win32 एपीआई है। मैं यूनिक्स सिस्टम के बराबर नहीं जानता - क्षमा करें। –

31

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

सी ++ अपवाद को पकड़ना या तो बहुत उपयोगी नहीं होगा। Std :: अपवाद से प्राप्त अपवाद पर प्रोग्राम मरने वाली बाधाएं बहुत पतली हैं। हालांकि यह हो सकता है। हार्डवेयर अपवादों के कारण सी/सी ++ ऐप में मृत्यु की अधिक संभावना है, एक्सेसवियोलेशन संख्या शून्य है। उन लोगों को फँसाने के लिए आपके मुख्य() विधि में __try और __except कीवर्ड की आवश्यकता होती है। दोबारा, बहुत कम संदर्भ उपलब्ध है, आपको मूल रूप से केवल एक अपवाद कोड मिला है। एक एवी आपको यह भी बताता है कि कौन सी सटीक स्मृति स्थान अपवाद का कारण बनता है।

यह सिर्फ एक क्रॉस-प्लेटफ़ॉर्म समस्या बीटीडब्ल्यू नहीं है, आप किसी भी प्लेटफॉर्म पर एक अच्छा स्टैक ट्रेस नहीं प्राप्त कर सकते हैं। ढेर पर चलने का कोई भरोसेमंद तरीका नहीं है, बहुत सारे अनुकूलन (जैसे फ्रेमपोइंटर चूक) हैं जो इसे एक खतरनाक यात्रा करते हैं। यह सी/सी ++ तरीका है: जितनी जल्दी हो सके इसे बनाओ, जब कोई उड़ाता है तो क्या हुआ कोई संकेत नहीं छोड़ें।

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

विंडोज़ पर, जो SetUnhandledExceptionFilter() को कॉल करके शुरू होता है, आप एक फ़ंक्शन पर कॉलबैक फ़ंक्शन पॉइंटर प्रदान करते हैं जो आपके प्रोग्राम को अनचाहे अपवाद पर मरने पर चलाएगा। कोई अपवाद, सी ++ के साथ ही एसईएच। आपका अगला संसाधन dbghelp.dll है, जो विंडोज डाउनलोड के लिए डिबगिंग टूल्स में उपलब्ध है। इसमें MiniDumpWriteDump() नामक एक एंट्रीपॉइंट है, यह एक मिनीडम्प बनाता है।

एक बार जब आप MiniDumpWriteDump() द्वारा बनाई गई फ़ाइल प्राप्त करते हैं, तो आप सुंदर सुनहरे होते हैं। आप विजुअल स्टूडियो में .dmp फ़ाइल लोड कर सकते हैं, लगभग एक प्रोजेक्ट की तरह। प्रक्रिया में लोड डीएलएल के लिए .pdb फ़ाइलों को लोड करने का प्रयास करते समय F5 और VS दबाएं। आप प्रतीक सर्वर को सेट करना चाहते हैं, यह बहुत अच्छा स्टैक निशान प्राप्त करने के लिए महत्वपूर्ण है। सब कुछ काम करता है, तो आप सही स्थान पर है, जहां अपवाद उत्पन्न हुआ था "पर एक" डिबग तोड़ "मिल जाएगा एक स्टैक ट्रेस के साथ

चीजें आपको बस इतना करना सुचारू रूप से इस काम करने के लिए:।।

  • बाइनरी बनाने के लिए बिल्ड सर्वर का उपयोग करें। इसे डिबगिंग प्रतीकों को धक्का देना आवश्यक है (।पीडीबी फाइलें) एक प्रतीक सर्वर पर ताकि जब आप मिनीडम्प डीबग करते हैं तो वे आसानी से उपलब्ध होते हैं।
  • डीबगर को कॉन्फ़िगर करें ताकि यह सभी मॉड्यूल के लिए डिबगिंग प्रतीक पा सके। आप माइक्रोसॉफ्ट से विंडोज के लिए डिबगिंग प्रतीक प्राप्त कर सकते हैं, आपके कोड के प्रतीक ऊपर वर्णित प्रतीक सर्वर से आने की जरूरत है।
  • अनचाहे अपवाद को फंसाने और मिनीडम्प बनाने के लिए कोड लिखें। मैंने SetUnhandledExceptionFilter() का उल्लेख किया है, लेकिन जो कोड minidump बनाता है वह क्रैश होने वाले प्रोग्राम में नहीं होना चाहिए। Minidump सफलतापूर्वक लिख सकते हैं कि बाधा काफी पतली हैं, कार्यक्रम की स्थिति अनिश्चित है। करने के लिए सबसे अच्छी बात यह है कि "गार्ड" प्रक्रिया चलाने के लिए जो नामित म्यूटेक्स पर नजर रखता है। आपका अपवाद फ़िल्टर म्यूटेक्स सेट कर सकता है, गार्ड मिनीडम्प बना सकता है।
  • ग्राहक की मशीन से स्थानांतरित करने के लिए मिनीडम्प के लिए एक तरीका बनाएं। हम उस के लिए अमेज़ॅन की एस 3 सेवा का उपयोग करते हैं, उचित दर पर टेराबाइट्स।
  • अपने डीबग डेटाबेस में मिनीडम्प हैंडलर को वायर करें। हम जिरा का उपयोग करते हैं, इसमें एक वेब-सेवा है जो हमें "हस्ताक्षर" के साथ पहले क्रैश के डेटाबेस के विरुद्ध क्रैश बाल्टी सत्यापित करने की अनुमति देती है। जब यह अद्वितीय होता है, या पर्याप्त हिट नहीं होते हैं, तो हम क्रैश मैनेजर कोड से अमेज़ॅन को मिनीडम्प अपलोड करने और बग डेटाबेस प्रविष्टि बनाने के लिए कहते हैं।

ठीक है, मैंने जो कंपनी के लिए काम किया है, उसके लिए मैंने यही किया है। बहुत अच्छी तरह से काम किया, यह हजारों से दर्जनों तक दुर्घटना बाल्टी आवृत्ति कम कर दिया। ओपन सोर्स ffdshow घटक के रचनाकारों को व्यक्तिगत संदेश: मैं आपको जुनून से नफरत करता हूं। लेकिन अब आप हमारे ऐप को और दुर्घटनाग्रस्त नहीं कर रहे हैं! Buggers।

+0

यह एफएफडीशो टीम का मतलब था, वे वेतन के बिना एक बहुत ही योग्य नौकरी कर रहे हैं और बहुत सारे आभारी उपयोगकर्ताओं (स्वयं शामिल) हैं। अन्यथा सहमत हैं, +1 –

+0

आपने क्रैश के लिए "हस्ताक्षर" कैसे बनाया? –

0

वास्तव में, boost :: diagnostic_information को विशेष रूप से "वैश्विक" पकड़ (...) ब्लॉक में उपयोग करने के लिए डिज़ाइन किया गया है, अपवादों के बारे में जानकारी प्रदर्शित करने के लिए जो इसे प्राप्त नहीं करना चाहिए था। हालांकि, ध्यान दें कि boost :: diagnostic_information द्वारा लौटाई गई स्ट्रिंग उपयोगकर्ता के अनुकूल नहीं है।

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