Join Now
Quality Rating:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)
This page was last modified 12:14, 4 July 2008.

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

Internal Links

 
Powered by MediaWiki
     
     RDF Facets:
     
     
     qfnZtypeQUqfnTypeZCommunityContentQ
     qfnZtypeQUqfnTypeZWebpageQ
     qfnZtypeQUqfnTypeZWikiContentQ
     qmarsZlanguageQUxhttpE3aE2fE2fswE2enokiaE2ecomE2flanguageE2d1E2fenX