【问题标题】:SigHandler causing program to not terminateSigHandler 导致程序不终止
【发布时间】:2019-08-06 07:46:03
【问题描述】:

目前我正在尝试创建一个信号处理程序,当它接收到 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 等还是很陌生,所以我对它在低级别的大部分工作方式非常不熟悉。

【问题讨论】:

  • 你应该在编码之前阅读sigaction(2)man 页面指的是signal(7),其中提到了signal-safety(7)。即使在 2019 年,RTFM 也是一个明智的格言。
  • 如果问题是针对 QNX 的,那么应该在其中提及 QNX

标签: c exit sigterm


【解决方案1】:

您的信号处理程序例程在概念上是错误的(它不仅仅使用异步信号安全函数)。 仔细阅读signal(7)signal-safety(7) 以了解原因。您的处理程序显然大部分时间都在工作,但仍然是undefined behavior

通常的技巧是(在您的信号处理程序中)设置一些volatile sig_atomic_t 变量并在信号处理程序之外测试该变量。 另一个可能的技巧是pipe(7) to self 技巧(Qt 文档很好地解释了it),您的信号处理程序只是对某些人执行write(2)is 异步信号安全)全局 file descriptor 由 eg 获得pipe(2)(或者可能是 Linux 特定的 eventfd(2)...)在安装该信号处理程序之前的程序初始化中。

Linux 特有的方法是将signalfd(2) 用于SIGTERM 并在您自己的event loop 中处理它(基于poll(2))。这个技巧在概念上是管道到自我的一种变体。但是signalfd 有一些缺点,网络搜索会很容易找到你。

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

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

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

【讨论】:

    【解决方案2】:

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

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

    如果您需要做一些信号处理程序中不允许的事情,他关于仅更改标志并在代码中测试它的建议是最好的方法。请注意,所有阻塞 posix 调用都可能被信号中断,因此如果您在阻塞调用(例如读取)时遇到错误,则测试您的原子变量是确定您是否收到信号的可靠方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多