如何捕捉panic
From Forum Nokia Wiki
如何捕捉panic
对,说的就是Panic。尽管就其本性来说,panic是“不可捕获的”,但仍有一种途径可以阻止它严重影响你的程序。
首先,为什么你要这样做呢?用况是什么?典型地,panic引起对应该已经在程序中更正的编程错误的注意。panic总是终止程序运行,并是故意这样设计的: 程序从“不可恢复的”运行阶段发生panic。因此,为什么我们需要捕获panic(假定我们能够这样做)?。
好了,至少有一个特殊的用处: 在测试框架中用于自动测试。在一个典型的单元测试框架中,比如,执行含有测试用例的测试集,若即使发生致命错误测试也不中断,这总是一个很好的功能。如果严重的编程错误不伤害其它的测试用例,那么某个测试用例的终止不影响其它用例的生命周期将是很理想的。
panic能被捕获吗?乍看起来,似乎User::SetExceptionHandler()能办到。但它却办不到。异常与panic不同。因此,安装一个新异常处理器不会使我们能捕获到panic,即使它使捕获一小部分异常成为可能(比如,访问违规或者说KERN-EXE 3)。
最终的解决方案: 让你的测试用例'运行在一个新线程中。一个你控制的新线程: 创建、销毁它,最重要的是监视它。经由RThread::Logon()你能够请求获知线程死亡正常与否。
下例演示了基于一个控制台的Exe,检测其他线程的死亡,显示类型及原因:
#ifndef THREADNOTIFIER_H #define THREADNOTIFIER_H #include <e32base.h> class CThreadNotifier : public CActive { public: CThreadNotifier(); ~CThreadNotifier(); void ConstructL(); void IssueRequest(); protected: void RunL(); void DoCancel(); TInt RunError(TInt aError); RUndertaker iUndertaker; TInt iThreadHandle; }; #endif
#include "ThreadNotifier.h" #include <e32cons.h> _LIT(KPanicMsg, "THREAD-NOTIFIER"); LOCAL_D CConsoleBase* console; CThreadNotifier::CThreadNotifier() : CActive(CActive::EPriorityStandard) { CActiveScheduler::Add(this); } void CThreadNotifier::ConstructL() { User::LeaveIfError(iUndertaker.Create()); } CThreadNotifier::~CThreadNotifier() { Cancel(); iUndertaker.Close(); } void CThreadNotifier::IssueRequest() { __ASSERT_ALWAYS(!IsActive(), User::Panic(KPanicMsg, 0)); iUndertaker.Logon(iStatus, iThreadHandle); SetActive(); } void CThreadNotifier::RunL() { if (iStatus == KErrDied) { RThread thread; thread.SetHandle(iThreadHandle); console->Printf(_L("Thread %S (%d) died (Type: %d, reason %d)\n"), &thread.Name(), (int)thread.Id(), thread.ExitType(), thread.ExitReason()); thread.Close(); } IssueRequest(); } void CThreadNotifier::DoCancel() { iUndertaker.LogonCancel(); } TInt CThreadNotifier::RunError(TInt /*aError*/) { return KErrNone; } LOCAL_C void callExampleL() { console = Console::NewL(_L("Thread Notifier"), TSize(KDefaultConsWidth, KDefaultConsHeight)); CleanupStack::PushL(console); CActiveScheduler* scheduler = new(ELeave) CActiveScheduler; CleanupStack::PushL(scheduler); CActiveScheduler::Install(scheduler); CThreadNotifier* notifier = new(ELeave) CThreadNotifier; CleanupStack::PushL(notifier); notifier->ConstructL(); notifier->IssueRequest(); CActiveScheduler::Start(); CleanupStack::PopAndDestroy(3, console); // console, scheduler, notifier } GLDEF_C TInt E32Main() { __UHEAP_MARK; CTrapCleanup* cleanup = CTrapCleanup::New(); TRAPD(error, callExampleL()); __ASSERT_ALWAYS(!error, User::Panic(KPanicMsg, error)); delete cleanup; __UHEAP_MARKEND; return 0; }
