SigHandler 导致程序不终止

SigHandler causing program to not terminate

目前我正在尝试创建一个信号处理程序,当它接收到 SIGTERM 信号时,它会关闭打开的网络套接字和文件描述符。

这是我的 SigHandler 函数

static void SigHandler(int signo){
    if(signo == SIGTERM){
      log_trace("SIGTERM received - handling signal");
      CloseSockets();
      log_trace("SIGTERM received - All sockets closed");

      if (closeFile() == -1)
        log_trace("SIGTERM received - No File associated with XXX open - continuing with shutdown");
      else
        log_trace("SIGTERM received - Closed File Descriptor for XXX - continuing with shutdown");

      log_trace("Gracefully shutting down XXX Service");
    } else {
      log_trace("%d received - incompatible signal");
      return;
    }

    exit(0);
}

下面这段代码位于 main

if (sigemptyset(&set) == SIGEMPTYSET_ERROR){
    log_error("Signal handling initialization failed");
  }
  else {
    if(sigaddset(&set, SIGTERM) == SIGADDSET_ERROR) {
      log_error("Signal SIGTERM not valid");
    }
    action.sa_flags = 0;
    action.sa_mask = set;
    action.sa_handler = &SigHandler;
    if (sigaction(SIGTERM, &action, NULL) == SIGACTION_ERROR) {
      log_error("SIGTERM handler initialization error");
    }
  }

当我发送 kill -15 PID 时,没有任何反应。该进程不会终止,也不会成为僵尸进程(无论如何都不应该)。但是,我确实在 SigHandler 函数中看到了打印的痕迹,所以我知道它在代码中达到了那个点。只是在exit(0)的时候好像不行

当我发送 SIGKILL(kill -9 PID)时,它会很好地终止进程。

抱歉,如果这含糊不清,我对 C 和 UNIX 等仍然很陌生,所以我对它在低级别的大部分工作方式非常不熟悉。

您的信号处理程序例程在概念上是错误的(它不仅仅使用异步信号安全函数)。仔细阅读signal(7) and signal-safety(7) to understand why. And your handler could apparently work most of the time but still be undefined behavior.

通常的技巧是设置(在您的信号处理程序中)一些 volatile sig_atomic_t 变量并在信号处理程序之外测试该变量。 另一个可能的技巧是 pipe(7) to self trick (the Qt documentation explains it well), with your signal handler just doing a write(2) (which is async-signal-safe) to some global file descriptor obtained by e.g. pipe(2) (or perhaps the Linux specific eventfd(2)...) 在安装该信号处理程序之前的程序初始化。

一个Linux的具体方法是使用signalfd(2) for SIGTERM and handle that in your own event loop (based upon poll(2))。这个技巧在概念上是 pipe to self one 的变体。但是signalfd也有一些缺点,网络搜索很容易找到你。

信号在概念上很难使用(有些人认为它们是 Unix 中的设计错误),尤其是在多线程程序中。

您可能想阅读 ALP 旧书。它对您的问题有一些很好的解释。

PS。如果您的系统是 QNX,您应该阅读它的文档。

您应该改用信号处理程序中的 _exit,这也会关闭所有文件。

另请(非常仔细地)阅读 Basile 的回答,并仔细查看允许在信号处理程序中使用的异步安全函数列表。

他关于仅更改标志并在代码中测试它的建议是如果您需要执行信号处理程序中不允许的操作的最佳方法。请注意,所有阻塞 posix 调用都可能被信号中断,因此如果您在阻塞调用(比如读取)中遇到错误,请测试您的原子变量是了解您是否收到信号的可靠方法。