当子有一个处理程序时,父shell没有获得SIGINT

时间:2015-11-17 19:54:09

标签: c linux signals

按Ctrl-C时,前台进程会收到SIGINT:

$ bash -c 'sleep 100; echo program died'
^C
$ echo $?
130

但是,如果程序安装了SIGINT处理程序,则父程序不会收到该信号。为什么呢?

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>

void sig_int(int sig_num)
{
    exit(1);
}

static struct sigaction sigact = { .sa_handler=sig_int };

int main(int argc, char *argv[])
{
    sigaction(SIGINT,&sigact,NULL);
    sleep(100);
    return 0;
}
bash没有死:

$ bash -c './a.out; echo program died'
^Cprogram died

Bash not trapping interrupts during rsync/subshell exec statements相关,但所有答案都有解决方法。

1 个答案:

答案 0 :(得分:1)

如果没有直接从终端

发送,shell将忽略SIGINT

这篇长篇post详细解释了正在发生的事情。在这里,我将尝试总结最重要的概念,并提出一个有效的解决方案。

事实证明,如果没有直接从终端发送(通过点击CTRL-C),shell被编程为忽略 SIGINT 。如果一个子进程拦截它,那么它必须通过使用 SIGINT 显式地自杀来引用,引用帖子:

  

“如果您没有捕获SIGINT,系统会自动执行右侧操作   对你而言:你的程序退出,调用程序得到了   在等待退出后,“I-exited-on-SIGINT”状态正确。

     

但是一旦你抓住了SIGINT,就必须采取正确的方法   在SIGINT处理程序中执行任何清理后退出。

     

决定SIGINT是否用于退出/中止目的,因此a   应该停止调用此程序的shellscript。这是有希望的   明显。如果你只需要在SIGINT上进行一些清理,然后退出   马上,答案是肯定的。

     

如果是这样,你必须通过退出告诉调用程序   “I-exited-on-SIGINT”状态。

     

没有其他方法可以做到这一点,而不是用自己来杀死自己   SIGINT信号。然后通过将SIGINT处理程序重置为SIG_DFL来完成   给自己发信号。

void sigint_handler(int sig)
{
  [do some cleanup]
  signal(SIGINT, SIG_DFL);
  kill(getpid(), SIGINT);
}

SIGINT处理程序

这是处理程序的工作版本,它拦截信号并正确地自杀(因此它不会打印'程序死亡')。 OTOH,如果你发送一个不同的信号,处理程序运行exit功能,你将再次看到屏幕上印有“程序死亡”。

void sig_int(int sig_num)
{
    if (sig_num == SIGINT) {
        printf("received SIGINT\n");
        signal(SIGINT, SIG_DFL);
        kill(getpid(), SIGINT);
    } else {
        exit(1);
    }
}

static struct sigaction sigact = { .sa_handler=sig_int };

int main(int argc, char *argv[])
{
    sigaction(SIGINT,&sigact,NULL);
    printf("go to sleep\n");
    sleep(3);
    printf("awaken\n");
    return 0;
}