我正在编写一个简单的shell程序,我可以在其中执行一些后台进程。我想使用像" killbg"这样的特定命令。能够SIGINT我执行的每个后台进程。我试过了:
setpgid(0,0)
创建仅包含后台进程的进程组
在pid=fork()
为0的条款中,即当我要执行子进程时。setpgid(0,0)
语句,我在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
}
}
}
}
我做错了什么?
答案 0 :(得分:0)
猜猜...... 1)您确定您的主要流程是不同群体的一部分吗? 2)由于stdin / stdout / stderr连接,您的孩子一旦死亡,您的父母可能会收到一个SIGPIPE。 SIGPIPE的默认信号动作是终止(参见signal(7))。
答案 1 :(得分:0)
查看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。