自定义SIGINT信号处理程序 - 即使捕获了信号,程序仍然终止

4
我正在使用 signal.hunistd.h 库,并遇到了一些问题。在下面的代码中,当我通过调用 CTRL-C 发送 SIGINT 信号给我的运行程序时,该信号被捕获。然而,当再次按下 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,看看是否效果更好。 - Marcus Müller
它在我的系统上运行良好。你的handle_signals.h文件里有什么?另外请注意,严格来说,信号处理程序不应调用其他系统函数,如printf,它只应设置一些标志变量之类的东西。 - Marian
@MarcusMüllerꕺꕺ:实际上有一个保证,即shell不会这样做:shell甚至看不到Ctrl+C(所有这些都由内核中的终端驱动程序代码处理)。 - psmears
1
@MarcusMüllerꕺꕺ printf(3) 不是异步信号安全的。它可能会因为各种原因调用malloc(3)free(3),例如初始化标准I/O库内部使用的缓冲区。它不应该在信号处理程序中使用。 - Filipe Gonçalves
@FilipeGonçalves:你是对的。这些天我总是错! - Marcus Müller
显示剩余4条评论
2个回答

4
不要使用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,但在我的脑海中它一直困扰着我。你知道为什么这个警告一直出现吗? - newbie
1
很奇怪,根据手册,你只需要 signal.h。也许可以发布另一个问题,附上详细的信息、编译器和操作系统版本? - Joni

3

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

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

这也是为什么你不应该再使用signal,而应该使用sigaction的原因之一。你可以在这里看到一个基本的使用sigaction的示例

确认这个可行。好的,知道了!我现在会去查看sigaction。 - newbie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接