1)先说明孤儿进程(orphan process)的概念: 一个其父进程已终止的进程称为孤儿进程(orphan process),这种进程由 init 进程”收养“。 本文中,讨论的是孤儿进程组: 2)孤儿进程组(orphaned process group): POSIX.1 将孤儿进程组定义为:该组中每个成员的父进程要么是该组中的一个成员,要么不是该组所属会话(session)的成员。 对孤儿进程组的另一种描述:一个进程组不是孤儿进程组的条件是,该组中有一个进程,其父进程在属于同一个会话(session)的另一个组中。 2.对孤儿进程的说明 父进程终止后,进程组成为孤儿进程组,POSIX.1 要求内核向新的孤儿进程组中处于停止状态的每一个进程发送挂断信号(SIGHUP),接着又向其发送继续运行信号(SIGCONT)。 unix(linux) 对挂断信号(SIGHUP)的系统默认动作是终止该进程,为此,必须提供一个信号处理程序以捕捉该信号。 3. 下面以一个父进程 + 一个子进程 组成的进程组为例,理解进程组成为孤儿进程组(本例中:该孤儿进程组就这一个子进程)后的行为。 下图是本例中的进程关系。 ![]() 示例代码:(对原文代码做了适当修改) #include stdio.h> #include stdlib.h> #include unistd.h> #include signal.h> #include errno.h> #define errexit(msg) do{ perror(msg); exit(EXIT_FAILURE); } while(0) static void sig_hup(int signo) { printf("SIGHUP received, pid = %d\n", getpid()); } static void sig_cont(int signo) { printf("SIGCONT received, pid = %d\n", getpid()); } static void sig_ttin(int signo) { printf("SIGTTIN 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)); } int main(int argc, char *argv[]) { char c; pid_t pid; setbuf(stdout, NULL); pr_ids("parent"); if ((pid = fork()) 0) { errexit("fork error"); } else if (pid > 0) { /* parent */ sleep(5); printf("parent exit\n"); exit(0); } else { /* child */ pr_ids("child...1"); signal(SIGCONT, sig_cont); signal(SIGHUP, sig_hup); signal(SIGTTIN, sig_ttin); kill(getpid(), SIGTSTP); //sleep(10); pr_ids("child...2"); if (read(STDIN_FILENO, &c, 1) != 1) { printf("read error from controlling TTY, errno = %d\n", errno); } printf("child exit\n"); } exit(0); } 将改程序编译成: m 程序执行结果: 1) 程序中使用 kill(getpid(), SIGTSTP); 使进程停止 [liumin@localhost orphan]$ ./m parent: pid = 15028, ppid = 8611, pgrp = 15028, tpgrp = 15028 child...1: pid = 15029, ppid = 15028, pgrp = 15028, tpgrp = 15028 parent exit SIGCONT received, pid = 15029 [liumin@localhost orphan]$ SIGHUP received, pid = 15029 child...2: pid = 15029, ppid = 1, pgrp = 15028, tpgrp = 8611 read error from controlling TTY, errno = 5 child exit [liumin@localhost orphan]$ ================================================= 2.将sleep 函数前的注释去掉,注释 kill 函数调用,就不会发送信号了(因为这个时候,进程不是处于停止状态,只有在停止状态时,孤儿进程组才会接收到 SIGHUP + SIGCONT 信号): [liumin@localhost orphan]$ ./m parent: pid = 15216, ppid = 8611, pgrp = 15216, tpgrp = 15216 child...1: pid = 15217, ppid = 15216, pgrp = 15216, tpgrp = 15216 parent exit [liumin@localhost orphan]$ child...2: pid = 15217, ppid = 1, pgrp = 15216, tpgrp = 8611 read error from controlling TTY, errno = 5 child exit [liumin@localhost orphan]$ 在进程中调用 pr_ids后,程序试图读标准输入。一般情况下,当后台进程组试图读控制终端时,则对该后台进程组产生 SIGTTIN 信号,其默认动作是停止进程。但是在这里,这是一个孤儿进程组,如果内核用此信号停止它,则此进程组中的进程就再也不会继续。 POSIX.1 规定,在这种情况下, read 函数返回出错,并将其errno 设置为 EIO。 |
|