按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相关,但所有答案都有解决方法。
答案 0 :(得分:1)
这篇长篇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;
}