孤儿进程即父进程先于子进程终止的进程,会被init接管,其父进程变为1。
孤儿进程组的概念:组中每个成员的父进程要么是该组的一个成员,要么不是该组所属会话的成员。
一个进程组不是孤儿进程组的条件:该组有一个进程,其父进程在同一会话的另一个组中。进程组不是孤儿进程组,在属于同一会话的另一个组中的父进程就有机会重启该组中停止的进程。
孤儿进程组的概念可以理解为组内所有的进程按照父子关系构建成树形结构,树根为init(1),如果组内所有进程都在此树的节点内覆盖,则说明这些进程构成孤儿进程组。
(1) 父进程终止后,POSIX.1要求向新的孤儿进程组的所有停止状态的每一个进程发送挂断信号SIGHUP,接着发送继续信号SITCONT。
(2) 停止状态的进程不是运行完的进程(此时是僵尸进程),是处于挂起等状态的进程,SIGTSTP就是将进程挂起。
(3) 父进程终止,子进程被置入后台进程组,不能操作标准输入、输出与出错。
程序实例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
static void
sig_hup(int signo)
{
printf("SIGHUP is received, pid=%d\n", getpid());
}
static void
pr_ids(char *name)
{
printf("%s: pid=%d, ppid=%d, pgrp=%d, tpgrp=%d\n",
name, getpid(), getppid(), getpgrp(), tcgetpgrp(STDIN_FILENO));
fflush(stdout);
}
int main(int argc, char **argv)
{
char c;
pid_t pid;
pr_ids("parent");
pid=fork();
if(pid>0)
{
sleep(5);
exit(0);
}
else
{
pr_ids("child");
signal(SIGHUP, sig_hup);
//signal(SIGHUP, SIG_DFL);
kill(getpid(), SIGTSTP);
pr_ids("child");
if(read(STDIN_FILENO, &c, 1) != 1)
{
printf("read error from controlling TTY, errno= %d\n", errno);
}
exit(0);
}
}
输出为:
parent: pid=4947, ppid=4913, pgrp=4947, tpgrp=4947
child: pid=4948, ppid=4947, pgrp=4947, tpgrp=4947
SIGHUP is received, pid=4948
child: pid=4948, ppid=1, pgrp=4947, tpgrp=4913
read error from controlling TTY, errno= 5
成为孤儿进程之后,父进程变为init(1),变为后台任务,无法读标准输入,对后台任务组产生SIGTTIN信号,此时read返回错误,errno设置为EIO。
SIGHUP的默认动作是终止进程,必须重新设定信号处理函数以捕捉该信号,如果设置为默认,即使用注释的signal(SIGHUP, SIG_DFL),输出变为
parent: pid=4968, ppid=4913, pgrp=4968, tpgrp=4968
child: pid=4969, ppid=4968, pgrp=4968, tpgrp=4968