2011-05-02 30 views
2

我想使用sigaction設置一個異常處理程序。它適用於第一個例外。但是,在第一個異常之後不會調用sigaction處理程序,並且第二個信號發生時程序會突然結束。爲什麼我的信號處理程序(引發異常)不會觸發多次?

#include <iostream> 
#include <signal.h> 
#include <exception> 
#include <string.h> 

typedef void (*SigactionHandlerPointer)(int iSignal, siginfo_t * psSiginfo, void * psContext); 

using namespace std; 

void SigactionHookHandler(int iSignal, siginfo_t * psSiginfo, void * psContext) 
{ 
    cout << "Signal Handler Exception Caught: std::exception -- signal : " << iSignal << " from SigactionHookHandler()" << endl; 

    throw std::exception(); 
} 

class A 
{ 
public: 
    A() {} 
    virtual ~A() {} 

    virtual void fnct1(); 
    virtual void fnct2() { fnct3(); } 
    virtual void fnct3() { fnct4(); } 
    virtual void fnct4(); 
}; 

void 
A::fnct1() 
{ 
    try { 
     fnct2(); 
    } 
    catch(std::exception &ex) { 
     cerr << "Signal Handler Exception Caught" << endl; 
    } 
    catch (...) 
    { 
     cerr << "Unknow Exception Caught: " << endl; 
    } 
} 

void 
A::fnct4() 
{ 
    *(int *) 0 = 0; // Access violation 
} 

int main() 
{ 
    struct sigaction oNewSigAction; 
    struct sigaction oOldSigAction; 

    memset(&oNewSigAction, 0, sizeof oNewSigAction); 

    oNewSigAction.sa_sigaction = SigactionHookHandler; 
    oNewSigAction.sa_flags  = SA_SIGINFO; 

    int iResult = sigaction(SIGSEGV, &oNewSigAction, &oOldSigAction); 

    cout << "sigaction installed handler with status " << iResult << endl; 

    A * pA = new A(); 

    cout << "Next message expected is : <<Signal Handler Exception Caught: std::exception>> to pass this test" << endl; 
    pA->fnct1(); 

    // Second exception will never be call the sigaction handler. 
    cout << "Next message expected is : <<Signal Handler Exception Caught: std::exception>> to pass this test" << endl; 
    pA->fnct1(); 

    return 0; 
} 

回答

7

信號和異常是彼此無關的。您使用的是什麼(從異步信號處理程序中拋出異常)只能在支持它的少數編譯器之間移植,例如GCC和Intel C/C++,並使用-fnon-call-exceptions。這就是說,你忘記做的是解鎖信號:當信號處理程序正在執行時,同一信號的傳遞被阻塞,並且當信號處理程序通過異常退出時它不會被解除阻塞。更改信號處理程序如下:

void SigactionHookHandler(int iSignal, siginfo_t * psSiginfo, void * psContext 
{ 
    cout << "Signal Handler Exception Caught: std::exception -- signal : " << iSignal << " from SigactionHookHandler()" << endl; 

    sigset_t x; 
    sigemptyset (&x); 
    sigaddset(&x, SIGSEGV); 
    sigprocmask(SIG_UNBLOCK, &x, NULL); 

    throw std::exception(); 
} 
+0

我使用GNU GCC和Intel編譯器。我使用了-fnon-call-exceptions選項。建議的補丁有效。但請注意,我更改了sigprocmask(SIG_UNBLOCK,&x,NULL);到pthread_sigmask(SIG_UNBLOCK,&x,NULL);因爲我有一個多線程應用程序。但我仍然感到困惑。 gcc-lib手冊指出:「......在任何情況下,當處理程序返回時,系統恢復進入處理程序之前的掩碼......」如果我評論throw std :: exception( )在原始代碼中,然後在調用信號處理程序之後,我確實返回到原始異常 – 2011-05-03 13:15:59

+0

(從以前的評論中繼續...),並且信號處理程序被一次又一次調用...因此,我沒有想到必須自己解除信號。我錯過了什麼? – 2011-05-03 13:19:05

+0

@Guy B:所以它看起來手冊是錯誤的,當它說「在任何情況下」,雖然人們可能會認爲拋出異常與「返回」不一樣。 FWIW,這再現了我在gcc 3.4.6,gcc 4.4.1,gcc 4.5.2和gcc 4.6.0。 – Cubbi 2011-05-03 14:26:58

2

標準C++沒有提到信號,也沒有提到它們如何與異常進行交互。你所要做的將完全針對你正在使用的操作系統平臺,也可能是你編譯你的代碼的特定編譯器。

+0

更具體地說,我使用Linux操作系統Ubuntu 10.10和GNU GCC 4.4.5編譯器。 – 2011-05-02 18:54:42

相關問題