2012-04-11 112 views
1

有没有什么方法记录,处理或以其他方式为进程终止的原因提供一些线索,涵盖尽可能多的终止事件?在Linux上记录使用C++进程终止的原因

我有一个用于我的应用程序的日志记录工具,并且每分钟记录很多消息。我几乎在一个超级try-catch块中运行了整个程序,所以我可以记录任何未处理的异常。我最近还尝试注册可能会终止进程的各种进程信号的处理程序。然而,应用程序仍然每天崩溃几次,我不知道为什么。

有多少其他致命事件可能无法记录或处理?我期望有一个正确的方法来做这件事,而不是一直处于黑暗中,当这个过程死于某种我还没有意识到的新事件时。

非常感谢。

+1

是否有任何额外的线程,线程子系统,进程外服务器? '超级try-catch块'不会捕获在这种环境中引发的错误。 – 2012-04-11 22:20:37

+0

是的,有多个线程。我已经为每个人添加了try-catch块。我甚至不知道什么是“进程外服务器”。从快速谷歌这看起来像Windows的东西,我可能是错的? – Pryo 2012-04-14 17:28:40

回答

2

你可以注册一个函数来处理意外的异常:

set_unexpected()

如果没有DELT与意志会导致应用程序调用TERMINAT()。

可以注册登录终端事情的函数:

set_terminate()

如果出口发生异常,您可以添加自己的atexit()的日志记录功能,会做的东西(设置一个标志,以便它只做东西然后在离开main之前设置标志)。

信号处理程序可能会非常棘手(特别是如果你希望它们是便携式的)。如果你使用它们,那么你在内部可以安全地进行操作时受到限制,所以我通常会限制自己设置一个全局标志,以便它们可以用普通代码处理(当然,如果你正在终止,那么这是非常有限的)。

2

有一个超级try/catch块意味着可捕获的异常不是未处理的。请注意,对于所有已启动的线程,您都需要这些块。

除此之外,您可以使用signal捕捉终止信号。它们是:

  • SIGABRT(信号中止)异常终止,例如由中止功能启动。
  • SIGFPE(信号浮点异常)错误的算术运算,例如零分或导致溢出的操作(不一定用于浮点操作)。
  • SIGILL(信号非法指令)无效的函数图像,例如非法指令。这通常是由于代码损坏或试图执行数据。
  • SIGINT(信号中断)交互式关注信号。一般由应用程序用户生成。
  • SIGSEGV(Signal Segmentation Violation)无效的存储访问:当一个程序试图读取或写入存储器之外时,它将被分配给它。 SIGTERM(信号终止)发送到程序的终止请求。
  • 由实现定义的信号,但大多数崩溃原因应该由这些覆盖。

此外,它可以是程序没有崩溃,而是从main返回终止或者(但我猜你已经拥有了覆盖)或通过以exit通话。在这种情况下,您可以检查程序的返回值并记录该值。

+0

+1指出我需要所有线程的try/catch块!我错过了。 – Pryo 2012-04-12 16:30:45

0

一个代码是值得很多的话:

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

sigint_handler(int s) { 
    std::cout<<"signal caught: "<<s<<std::endl; 
    ::exit(-1); 
} 

void setup_signal() { 
    struct sigaction sigIntHandler; 
    sigIntHandler.sa_handler = sigint_handler; 
    sigemptyset(&sigIntHandler.sa_mask); 
    sigIntHandler.sa_flags = 0; 
    sigaction(SIGINT, &sigIntHandler, NULL); 
    sigaction(SIGTERM, &sigIntHandler, NULL); 
} 

int main() { 
    setup_signal(); 
    /* do stuff */ 
    return 0; 
} 
当然

,这只需要照顾SIGINT/SIGTERM信号。你也必须用atexit(),set_terminate,super try/catch等等来更新这个代码。你可以找到。如果你遇到段错误/总线错误/无论什么......好吧,你注定了:)

+0

绝对不要那样做。你不应该像写信号处理程序中的文件那样复杂。设置一个标志并在ataxit()注册函数中处理这种情况。 – 2012-04-11 22:42:44

+0

你说得对,但是atexit()会处理杀/短信?当然,我同意你的观点,不应该在这些情况下写入文件,而应该使用stdout/stderr并将其重定向到父进程中的文件中。 – zmo 2012-04-11 22:48:36

2

下面是我在我的程序中使用的,它适用于我......每当我的程序崩溃时,它会将崩溃站点的堆栈跟踪打印到标准输出(大概是重定向到可以读取它的文件等)后来)。

请注意,您可能需要在Makefile中的CXXFLAGS和/或LFLAGS中将-rdynamic作为标志传递,以确保堆栈跟踪包含人类可读的函数名称。

#include <stdio.h> 
#include <signal.h> 
#include <execinfo.h> 

void PrintStackTrace() 
{ 
    void *array[256]; 
    size_t size = backtrace(array, 256); 
    char ** strings = backtrace_symbols(array, 256); 
    if (strings) 
    { 
     printf("--Stack trace follows (%zd frames):\n", size); 
     for (size_t i = 0; i < size; i++) printf(" %s\n", strings[i]); 
     printf("--End Stack trace\n"); 
     free(strings); 
    } 
    else printf("PrintStackTrace: Error, could not generate stack trace!\n"); 
} 

static void CrashSignalHandler(int sig) 
{ 
    // Uninstall this handler, to avoid the possibility of an infinite regress 
    signal(SIGSEGV, SIG_DFL); 
    signal(SIGBUS, SIG_DFL); 
    signal(SIGILL, SIG_DFL); 
    signal(SIGABRT, SIG_DFL); 
    signal(SIGFPE, SIG_DFL); 

    printf("CrashSignalHandler called with signal %i... I'm going to print a stack trace, then kill the process.\n", sig); 
    PrintStackTrace(); 
    printf("Crashed process aborting now.... bye!\n"); 
    fflush(stdout); 
    abort(); 
} 

int main(int argc, char ** argv) 
{ 
    signal(SIGSEGV, CrashSignalHandler); 
    signal(SIGBUS, CrashSignalHandler); 
    signal(SIGILL, CrashSignalHandler); 
    signal(SIGABRT, CrashSignalHandler); 
    signal(SIGFPE, CrashSignalHandler); 

    [...remainder of your program goes here...] 
}