如何仅在 C 中将 SIGINT 发送到后台进程
Posted
技术标签:
【中文标题】如何仅在 C 中将 SIGINT 发送到后台进程【英文标题】:How to send SIGINT to background processes only in C 【发布时间】:2015-03-02 17:20:05 【问题描述】:我正在编写一个简单的 shell 程序,我可以在其中执行一些后台进程。我希望使用像“killbg”这样的特定命令能够对我执行的每个后台进程进行 SIGINT。我试过了:
-
使用
setpgid(0,0)
创建一个仅由后台进程组成的进程组
在 pid=fork()
为 0 的子句中,即当我要执行子进程时。
setpgid(0,0)
语句后得到的进程组 'pgid',我在 kill 函数中使用,例如 kill(pgid, 2)
。
不幸的是,整个程序被中断,后台任务仍在运行。
以下是相关代码:
while(1)
fgets.. //user input for command
// Kill background processes
if(strcmp(execArgs[0], "killbg") == 0) //execArgs argument array for execve
kill(pgid, 2);
perror("");
pid=fork();
// Error in fork
if(pid <= -1)
perror("Error with fork.\n");
exit(EXIT_FAILURE);
// Child process
else if(pid == 0)
if(execBG == TRUE) // execBG true If user wants to run command in background
setpgid(0,0);
pgid = getpgid(pid);
execve(execArgs[0], execArgs, NULL);
fprintf(stderr, "Not a valid command! Remember the full path.\n");
// Parent process
else
if(execBG==FALSE)
waitpid(-1, &status, NULL);
else
; // if background process, don't wait for the child
我做错了什么?
【问题讨论】:
你在子进程中设置pgid
,在父进程中对pgid
执行kill()
,父进程不知道子进程为pgid
设置了什么。
【参考方案1】:
只是猜测... 1)您是否确保您的主要流程是不同组的一部分? 2)一旦您的孩子因 stdin/stdout/stderr 连接而死亡,您的父母可能会收到 SIGPIPE。 SIGPIPE 的默认信号动作是终止(参见 signal(7))。
【讨论】:
不,你不明白。父母被我的杀戮功能打断了。我是否确定它是否是不同的组?这正是我的问题的一部分。我不信,问怎么做。 @ot0:如果想确保不被视为粗鲁,可以用“我似乎表达得不够好”而不是“你不明白”。【参考方案2】:查看 POSIX kill()
函数的规范,了解如何向进程组发送信号:
如果pid大于0,sig将被发送到进程ID等于pid的进程。
如果pid为0,sig应该被发送到进程组ID等于进程组ID的所有进程(不包括未指定的系统进程集)发送者,并且进程有权为其发送信号。
如果pid 为-1,则sig 应发送到所有进程(不包括未指定的系统进程集),该进程有权发送该信号。
如果pid 为负数,但不是-1,则sig 应发送给进程组ID 等于的所有进程(不包括未指定的系统进程集) pid 的绝对值,进程有权发送信号。
因此,要将SIGINT
发送到进程组,您需要调用kill(-pgrp, SIGINT)
。您还应该始终检查系统调用的返回值,以便知道它何时失败。
我观察到如果execve()
失败(也就是返回),您会打印一条错误消息——这很好!此时退出程序通常也是正确的。否则,您往往会有一个额外的过程来尝试读取您的终端输入,这很容易造成混乱和混乱。
注意kill(pgrp, 2); perror("");
不好,因为errno
可以在调用kill()
之前设置为非零值,或者通过kill()
设置,即使它不报告失败。您必须测试系统调用的返回值以了解errno
是否相关,并且您应该仅在相关时调用perror()
。 (假设你应该调用perror()
;IMO,这是错误报告功能的一个相当蹩脚的借口,但如果使用得当,总比没有好。)
您的waitpid()
电话不安全。第三个参数是一个整数,而不是一个指针。此外,您可以在后台运行多个子进程;该代码只等待一个退出 - 任何子进程。您几乎可以肯定那里需要一个循环,并且可能也需要 WNOHANG。
【讨论】:
感谢您的评论。我正在尝试理解所有这些概念,以及在另一个 post 上阅读您的答案。我认为在 kill 函数之前我需要了解将子进程和父进程分成不同组的概念。以上是关于如何仅在 C 中将 SIGINT 发送到后台进程的主要内容,如果未能解决你的问题,请参考以下文章
Nodejs:将 Ctrl+C 发送到 Windows 上的子进程
Python 在 Windows 上发送 SIGINT 信号子进程
linux信号 SIGINT SIGTERM SIGKILL