Join Now
Quality Rating:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)
Expertise Level:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)

This page was last modified 11:58, 25 December 2007.

Как перехватить панику

From Forum Nokia Wiki

Перевод с английского, оригинальная статья находится здесь.


Строго говоря, паники не предназначены для того чтобы их перехватывали, однако, в некоторых случаях это необходимо. Для начала выясним, что это за случаи, в чем смысл. Обычно паники используются для обозначения программных ошибок которые должны быть уже исправлены и, в собранной для распространения версии программы, не должны встречаться. Паника всегда завершает выполнение программы так как программа входит в состояние из которого не может корректно продолжить свое выполнение. Для чего же перехватывать паники, если это вообще возможно ?

Есть по крайней мере одна специфическая причина - автоматизированное тестирование программы. Предположим, для проведения тестирования используется определенный набор тестов которые выполняются последовательно. Тогда, если во время выполнения одного из них возникнет паника, основной процесс, который выполняет тестирование будет прерван и оставшиеся тесты не будут выполнены. Поэтому, для того чтобы тестирование всегда проходило корректно и доходило до конца, необходимо перехватывать паники.

Можно ли перехватить панику ? На первый взгляд это можно сделать с помощью вызова User::SetExceptionHandler(). Но это утверждение ошибочно: исключения и паники - разные вещи. Поэтому установка нового обработчика исключения не позволит перехватывать ВСЕ паники, разве что только некоторые (например KERN-EXEC 3).

Общее решение проблемы - выполнение тестов на отдельной нити. Отдельная нить находится под вашим полным контролем: Вы можете создавать, уничтожать и, что важно, мониторить ее состояние. Вы можете подписаться на оповещение в случае если нить будет уничтожена обычным способом или воспользоваться вызовом RThread::Logon(). Кроме того, используя метод RThread::ExitReason() Вы можете получить информацию о том как и когда нить завершила свое выполнение. Даже в случае возникновения паники в одном из тестов, основная нить вашего тестирующего приложения может нормально продолжить свою работу.

Ниже приведен пример консольного приложения(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;
}
Related Discussions
Thread Thread Starter Forum Replies Last Post
Поворот на телевизоре картинки выдаваемой Nokia N95 aragsm Russian Developer Forum - Форум Российских разработчиков 5 2008-03-14 09:49
Делаем основной цикл игры Ecconaut Russian Developer Forum - Форум Российских разработчиков 17 2007-12-12 04:32
Вопрос про XML vanek_sck Russian Developer Forum - Форум Российских разработчиков 3 2007-12-22 08:31
Прорисофка mif файла fly9296404 Russian Developer Forum - Форум Российских разработчиков 3 2008-05-27 06:11
How to make a full-screen application using Symbian C++ midday Russian Developer Forum - Форум Российских разработчиков 6 2007-12-10 12:04
 
Powered by MediaWiki
     
     RDF Facets:
     
     
     qfnZtypeQUqfnTypeZCommunityContentQ
     qfnZtypeQUqfnTypeZWebpageQ
     qfnZtypeQUqfnTypeZWikiContentQ
     qmarsZlanguageQUxhttpE3aE2fE2fswE2enokiaE2ecomE2flanguageE2d1E2fenX