Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

如何捕捉panic

From Wiki
Jump to: navigation, search
Article Metadata

文章
dougcn 在 04 Jul 2008 创建
最后由 hamishwillee 在 15 Dec 2011 编辑

如何捕捉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;
}

Internal Links

This page was last modified on 15 December 2011, at 05:46.
69 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×