以下是执行的程序的来源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;
}
Run Code Online (Sandbox Code Playgroud)
请注意对的调用setpgid(0, 0)。
在shell中运行时(sh或bash),我期望:
cat,并且但是,发生的是:
cat没有问题,但是T为ps),并且SIGINT,SIGSTOP或者SIGQUIT,只被冻死SIGKILL。当呼叫setpgid()被注释掉时,一切都按预期进行。
我怀疑该行为是由以下原因引起的:
cat正在尝试阅读stdin并正在等待(因此已停止),但是bash,然后传递给上面的程序,但是不传递给cat,这可能是由于其不同的进程组而导致bash无法识别其子孙cat。当然,删除setpgid()呼叫是最简单的解决方案。不幸的是,有一些原因。主要是为了拦截父级中的某些信号(例如SIGINT或SIGSTOP)。换句话说,a <Ctrl-C>不应杀死,cat而是以某种方式通知上面的程序。(上面的程序中没有信号处理程序,是的,出于说明目的。)
我想问一下:
cat接收来自stdin的输入?正如评论中所建议的,前台进程组(假设所有 STDIN)可以通过 进行更改tcsetpgrp()。
该函数也可以从子进程中调用。否则,父级将不得不等待子级成功调用setpgid(),并且会发生并发问题。
然而,正如这个SO问题中所描述的,当子进程(还不是前台)调用时tcsetpgrp,它会收到一个SIGTTOU信号,根据手册tcsetpgrp。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;
}
Run Code Online (Sandbox Code Playgroud)
现在底层cat开始和终端交互了,问题就解决了。
uuu@hhh:~$ ./a
sajkfla
sajkfla
wjkelfaw
wjkelfaw
reaped PID = 774
uuu@hhh:~$ ./a
Run Code Online (Sandbox Code Playgroud)