apue第九章 孤儿进程组例子

Posted yinkw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了apue第九章 孤儿进程组例子相关的知识,希望对你有一定的参考价值。

 

1. 为什么会有孤儿进程组的概念,APUE没写清楚,但是GNU有规定:

孤儿进程组不可以获得终端,这是为了保证控制进程死掉后他的终端可以安全分配给新session。posix要求向新孤儿进程组中停止状态的进程(也有说是孤儿进程组里所有进程)发送SIGHUP(挂起)信号和SIGCONT(继续)信号。首先处理SIGHUP信号,系统默认处理是终止进程,然而也可以另行处理这样进程会继续执行,但任不可以再获得终端。

2. 书本代码示例apue.3e/relation/orphan3.c较费解

#include "apue.h"
#include <errno.h>

static void
sig_hup(int signo)
{
    printf("SIGHUP received, pid = %ld
", (long)getpid());
}

static void
pr_ids(char *name)
{
    printf("%s: pid = %ld, ppid = %ld, pgrp = %ld, tpgrp = %ld
",
        name, (long)getpid(), (long)getppid(), (long)getpgrp(),
        (long)tcgetpgrp(STDIN_FILENO));
    fflush(stdout);
}

int
main(void)
{
    char    c;
    pid_t    pid;

    pr_ids("parent");
    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid > 0) {    /* parent */
        sleep(5);        /* sleep to let child stop itself */
    } else {            /* child */
        pr_ids("child");
        signal(SIGHUP, sig_hup);    /* establish signal handler */
        kill(getpid(), SIGTSTP);    /* stop ourself */
        pr_ids("child");    /* prints only if we‘re continued */
        if (read(STDIN_FILENO, &c, 1) != 1)
            printf("read error %d on controlling TTY
", errno);
    }
    exit(0);
}

这里,father等待5秒后狗带,child运行结果如下:

[[email protected] relation]$ ./orphan3
parent: pid = 15877, ppid = 15811, pgrp = 15877, tpgrp = 15877 // father是组长,也是前台进程组ID,father的father是shell,shell pid=15811
child: pid = 15878, ppid = 15877, pgrp = 15877, tpgrp = 15877  // child是组员,当前这个进程组占据了终端。结果输出在这里停了几秒,然后才打印下一句“SIGHUP received”
[[email protected] relation]$ SIGHUP received, pid = 15878         // 进程组先退出终端,然后又在终端打印SIGHUP
child: pid = 15878, ppid = 1, pgrp = 15877, tpgrp = 15811      // 前台进程组已经不是father了,说明终端又交给了shell
read error 5 on controlling TTY                         // 这里是child试图读标准输入read(STDIN_FILENO, &c, 1),触发了异常。
^C                                     // child似乎没有走到exit(0)

原因分析如下:

1. kill(15878, SIGTSTP)并不是要child杀死自己,而是暂停前台作业。

技术图片

2. father自然死亡后,child成为孤儿进程,被init收养,因此ppid=1。

 child也成为进程组15877也成为孤儿进程组,因此收到SIGHUP信号(之后还会收到SIGCONT信号,表示继续)。

3. 子进程处理SIGHUP信号的时候,已经是孤儿进程组成员了,没有权限刷到标准输出,为什么成功打印了“SIGHUP received, pid = 15878”呢?同样的疑惑,为什么child能在终端打印“read error %d on controlling TTY ”呢?关于这个疑问其实apue也有写,POSIX.1只对读控制终端作出限制。

技术图片

 所以说,gnu对孤儿进程组的定义里access一词的意思是“读”,孤儿进程组成员试图读取控制终端时才抛EIO,对写终端未做规定。

技术图片

小结

这个故事说明,像W.Richard Stevens这种处在技术书籍第一列队的作者,写书不会含糊跳过的,因此一种省时间的看这位老哥的书的方式是,在书本里找答案,不要自信跳过。

以上是关于apue第九章 孤儿进程组例子的主要内容,如果未能解决你的问题,请参考以下文章

孤儿进程与僵尸进程

孤儿进程与僵尸进程

Python之旅.第九章.并发编程

快速理解孤儿进程和僵尸进程

APUE | 08进程控制

第九章 原子性