以下是执行cat
的程序的来源:
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
pid_t pid = fork();
if (!pid) {
// create a new process group
setpgid(0, 0);
execlp("cat", "cat", NULL);
}
pid_t reaped = wait(NULL);
printf("reaped PID = %d\n", (int) reaped);
return 0;
}
注意对setpgid(0, 0)
的呼叫。
在shell(sh
或bash
)中运行时,我期望:
cat
的子级进程,并且但是,发生的事情是:
cat
没问题,但是T
中具有进程状态代码ps
),并且SIGINT
,SIGSTOP
或SIGQUIT
中的任何一个都没有反应,只是被SIGKILL
杀死。当对setpgid()
的呼叫被注释掉时,一切都按预期进行。
我怀疑该行为是由以下原因引起的:
cat
试图读取stdin并正在等待(因此已停止),但是bash
,然后传递给上面的程序,但是不传递给cat
,这可能是因为bash
无法识别其子孙{{ 1}},因为它的处理组不同。当然,删除cat
调用是最简单的解决方案。不幸的是,有一些原因。主要是为了拦截父级中的某些信号(例如SIGINT或SIGSTOP)。换句话说,setpgid()
不应杀死<Ctrl-C>
,而应以某种方式向上面的程序发出信号。 (上面的程序中没有信号处理程序,是的,出于说明目的。)
我想问:
cat
接收来自stdin的输入?答案 0 :(得分:1)
如评论中所建议,可以通过tcsetpgrp()
更改前台进程组(假定所有STDIN)。
该功能也可以从子级调用。否则,父级将不得不等待子级成功进行setpgid()
调用,并且会发生并发问题。
但是,根据tcsetpgrp
的手册,如本SO question中所述,当孩子(尚未到前台)调用tcsetpgrp
时,它将收到SIGTTOU信号。 。 SIGTTOU的默认操作是停止该过程,应该手动将其忽略。
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
int main()
{
// ignore SIGTTOU
signal(SIGTTOU, SIG_IGN);
pid_t pid = fork();
if (!pid) {
// create a new process group
setpgid(0, 0);
tcsetpgrp(STDIN_FILENO, getpgid(0));
execlp("cat", "cat", NULL);
}
pid_t reaped = wait(NULL);
printf("reaped PID = %d\n", (int) reaped);
return 0;
}
现在底层的cat
开始与终端进行交互,问题得以解决。
uuu@hhh:~$ ./a
sajkfla
sajkfla
wjkelfaw
wjkelfaw
reaped PID = 774
uuu@hhh:~$ ./a