【问题标题】:Log the reason for process termination with C++ on Linux在 Linux 上使用 C++ 记录进程终止的原因
【发布时间】:2012-04-24 06:37:14
【问题描述】:

是否有任何方法可以记录、处理或以其他方式留下有关进程终止原因的一些线索,涵盖尽可能多的导致终止的事件?

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

我可能无法记录或处理多少其他致命事件?我希望有一种适当的方法来做到这一点,而不是在进程因某些我还不知道的新型事件而终止时一直处于黑暗之中。

非常感谢。

【问题讨论】:

  • 是否有额外的线程、线程子系统、进程外服务器? “超级 try-catch 块”不会捕获在此类环境中引发的错误。
  • 是的,有多个线程。我现在为每一个添加了 try-catch 块。我什至不知道什么是“进程外服务器”。从快速谷歌上看,这看起来像是 Windows 的东西,我可能错了吗?

标签: c++ linux logging handle terminate


【解决方案1】:

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

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

  • SIGABRT(信号中止)异常终止,例如由中止函数启动。
  • SIGFPE(信号浮点异常)错误的算术运算,例如零除或导致溢出的运算(不一定是浮点运算)。
  • SIGILL(信号非法指令)无效的函数映像,例如非法指令。这通常是由于代码损坏或尝试执行数据所致。
  • SIGINT(信号中断)交互式注意信号。通常由应用用户生成。
  • SIGSEGV(信号分段违规)对存储的无效访问:当程序试图在分配给它的内存之外读取或写入时。 SIGTERM(信号终止)向程序发送终止请求。
  • 由实现定义的信号,但大多数崩溃原因都应包含在这些信号中。

另外,程序可能没有崩溃,而是通过从 main 返回(但我猜你已经知道了)或通过调用 exit 来终止。在这种情况下,您可以检查程序的返回值并将其记录下来。

【讨论】:

  • +1 指出我需要所有线程的 try/catch 块!我错过了。
【解决方案2】:

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

set_unexpected()

如果不是 delt 将导致应用程序调用 terminat()。

您可以注册一个函数来记录终止时的内容:

set_terminate()

您可以添加自己的 atexit() 日志记录函数来执行某些操作(设置一个标志以便它仅在异常退出时才执行操作,然后在离开 main 之前设置该标志)。

信号处理程序可能很棘手(特别是如果您希望它们是可移植的)。如果你使用它们,你在里面可以安全地做的事情是有限的,所以我通常限制自己设置一个全局标志,以便它们可以由普通代码处理(当然,如果你要终止,那么这是非常有限的)。

【讨论】:

    【解决方案3】:

    一个代码胜过千言万语:

    #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、超级 try/catch 等更新此代码。您可以找到。万一你遇到段错误/总线错误/无论如何......好吧,你注定要失败:)

    【讨论】:

    • 绝对不要那样做。您不应该做任何像在信号处理程序中写入文件那样复杂的事情。在 ataxit() 注册函数中设置一个标志并处理这种情况。
    • 你是对的,但是 atexit() 会在 kill/term 信号上工作吗?当然,我同意你的看法,在这种情况下不应该写入文件,而应该使用 stdout/stderr 并将其重定向到父进程中的文件中。
    【解决方案4】:

    看看这个问题。 How to find the reason for a dead process without log file on unix?

    您将看到使用 bash 获取进程的退出代码比使用信号处理程序或任何类型的退出回调更容易

    【讨论】:

      【解决方案5】:

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

      请注意,您可能需要在 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...]
      }
      

      【讨论】:

        猜你喜欢
        • 2021-03-16
        • 1970-01-01
        • 1970-01-01
        • 2014-08-13
        • 1970-01-01
        • 1970-01-01
        • 2020-11-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多