【问题标题】:Custom SIGINT signal handler - Program still terminates even after signal is caught自定义 SIGINT 信号处理程序 - 即使在信号被捕获后程序仍会终止
【发布时间】:2015-07-08 06:45:42
【问题描述】:

我正在使用 signal.hunistd.h 库,但遇到了一些问题。在下面的代码中,当我通过调用CTRL-CSIGINT 信号发送到正在运行的程序时,该信号被捕获。但是,当再次按下CTRL-C 时,程序会终止。据我了解,每次按CTRL-C时都应该打印打印语句"Received signal 2"

是我对这个信号的理解不正确,还是我的代码有错误?

感谢您的意见!

#include "handle_signals.h"


void sig_handler(int signum)
{
    printf("\nReceived signal %d\n", signum);
}

int main()
{
    signal(SIGINT, sig_handler);
    while(1)
    {
        sleep(1);
    }
    return 0;
}

终端输出:

xxx@ubuntu:~/Dropbox/xxx/handle_signals$ ./handle_signals 
^C
Received signal 2
^C
xxx@ubuntu:~/Dropbox/xxx/handle_signals$ 

编辑:这是我包含的标题

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void sig_handler(int signum);

感谢您的回复。现在通读一遍!

【问题讨论】:

  • 你没有“发送 ctrl+c”,你按那个。然后发生的事情是按键被解释为将 SIGINT 发送到您的进程。不能保证您的 shell 不会认为“嗯,连续两个 ctrl+c,最好发送 SIGKILL”之类的。尝试使用killall -SIGINT yourprogram,看看效果是否更好。
  • 它在我的系统上运行良好。您的文件handle_signals.h 中有什么内容?另请注意,严格来说,信号处理程序不应调用像printf这样的其他系统函数,它应该只设置一些标志变量左右。
  • @Marian:不仅严格来说,在信号处理程序中做大量 IO 绝不是一个好主意。但是,printf 不是一个系统函数(它是一个 libc 函数),而是一个内部调用 write 并且可能调用 fdatasync 的函数。有关允许的系统调用的参考,请运行man 7 signalwritefdatasync 允许在信号处理程序中使用。这并不意味着这是一个好主意——信号基本上可能会在执行过程中随处发生,即使只是有一些东西要刷新到标准输出,所以你会得到信号处理程序和常规输出的完美结合。
  • @MarcusMüllerꕺꕺ:实际上可以保证 shell 不会那样做:shell 甚至看不到 Ctrl+C(这一切都由内核中的终端驱动程序代码处理)。
  • @MarcusMüllerꕺꕺ printf(3) 不是异步信号安全的。它可能出于各种原因调用malloc(3)free(3) - 例如,初始化标准I/O 库内部使用的缓冲区。它不应该在信号处理程序中使用。

标签: c linux signals posix


【解决方案1】:

不要使用signal,使用sigaction

signal() 的行为因 UNIX 版本而异,并且在历史上因 Linux 的不同版本而异。 避免使用它:改用 sigaction(2)。

http://man7.org/linux/man-pages/man2/signal.2.html

在最初的 UNIX 系统中,当通过信号传递调用使用 signal() 建立的处理程序时,信号的处置将重置为 SIG_DFL,并且系统不会阻止传递更多实例信号。

Linux 实现了相同的语义:在传递信号时重置处理程序。

【讨论】:

  • 我已经尝试成功使用 sigaction。但是,无论我包含什么,我都会不断收到 sigaction 的隐式声明警告。我会继续使用 sigaction,但在我的脑海里,它一直困扰着我。你知道为什么这个警告一直出现吗?
  • 这很奇怪,根据手册页你只需要signal.h。也许发布另一个带有详细消息和编译器和操作系统版本的问题?
【解决方案2】:

signal 在接收到第一个信号时的行为因不同的实现而异。通常,它需要在接收到信号后重新安装处理程序,因为处理程序被重置为其默认操作:

void sig_handler(int signum)
{  
    signal(SIGINT, sig_handler);
    printf("\nReceived signal %d\n", signum);
}

这是您不应再使用signal 并使用sigaction 的原因之一。您可以在此处查看using sigaction 的简单示例。

【讨论】:

  • 确认这有效。很高兴知道这一点!我现在将检查 sigaction。
猜你喜欢
  • 1970-01-01
  • 2015-09-13
  • 2013-12-21
  • 1970-01-01
  • 2013-07-26
  • 1970-01-01
  • 2017-09-05
  • 1970-01-01
  • 2011-01-26
相关资源
最近更新 更多