【发布时间】:2015-11-19 16:10:08
【问题描述】:
我正在用 C 编写一个基本的 unix shell,我想在 shell 中捕获 Cntrl-C 信号并将它们仅传递给前台进程,而不是后台进程。 shell 本身应该继续运行(确实如此),并且后台进程应该忽略 Cntrl-C 并且只被专门发送给它们的终止信号杀死,可能通过命令行“kill pid”。但是,前台和后台进程都应该使用 SIGCHLD 触发处理程序。然而,现在,shell 捕获了 Cntrl-C 信号,并且似乎正确地识别出没有将信号传递给的前台进程,但后台进程仍然死亡。
我尝试将后台进程的组 id 设置为其他值,这解决了问题,但它产生了一个新问题。当我这样做时,我的信号处理程序在后台进程完成时不再捕获信号。
到目前为止,我已经查看了 SIGINT 的手册页,我已经阅读了大约 20 个 SO 答案,我尝试将子项的组 id 设置为与父项不同的值(解决了问题,但现在child 不能再向 parent 发送 SIGCHLD),并且当我运行后台进程时,我已经检查了 childid != 前台进程和 foregroundProcess == 0 。但是后台进程仍然被杀死。有任何想法吗?
我认为我的问题出在信号处理程序的某个地方,但不太确定:
主要内容:
struct sigaction sa;
sa.sa_handler = &handleSignal; /*passing function ref. to handler */
sa.sa_flags = SA_RESTART;
sigfillset(&sa.sa_mask); /*block all other signals while handling sigs */
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
handleSignal 看起来像这样:
void handleSignal(int signal){
int childid;
switch (signal) {
/*if the signal came from a child*/
case SIGCHLD:
/*get the child's id and status*/
childid = waitpid(-1,&childStatus,0);
/*No action for foreground processes that exit w/status 0 */
/*otherwise show pid & showStatus */
if ((childid != foregroundProcess)){
printf("pid %i:",childid);
showStatus(childStatus);
fflush(stdout);
}
break;
/* if signal came from somewhere else, pass it to foreground child */
/* if one exists. */
default:
printf("Caught signal: %i and passing it", signal);
printf(" to child w/pid: %i\n\n:", foregroundProcess);
fflush(stdout);
/*If there is a child, send signal to it. */
if (foregroundProcess){
printf("trying to kill foreground.\n");
fflush(stdout);
kill(foregroundProcess, signal);
}
}
}
【问题讨论】:
-
在不相关的说明中,如果您没有更改
stdout的缓冲模式,只要您以换行符结束所有输出,您就不需要显式刷新它。stdout默认是行缓冲的。 -
谢谢约阿希姆。由于 printf 用于调试目的,因此我在对缓冲区进行 fflush 时格外小心。我不希望某些实际到达的打印行不打印,因为同时另一个过程做了一些奇怪的事情。无论如何,所有这些 printf 都可能在最终产品中消失。