• apue第九章之孤儿进程组


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

    孤儿进程组不可以获得终端,这是为了保证控制进程死掉后他的终端可以安全分配给新session。posix要求向新孤儿进程组中停止状态的进程(GNU说是给孤儿进程组里所有进程发消息,而APUE中文版说是给停止状态的进程发消息)发送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运行结果如下:

    [karenyin@host 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”
    [karenyin@host 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这种咖位的技术书籍作者,写书不会含糊其辞的。看书的时候不要自信跳过,不然有可能浪费时间。

  • 相关阅读:
    Yii2框架之旅(三)
    Yii2框架之旅(二)
    Redis本地集群搭建(5版本以上)
    Redis入门笔记
    Java如何使用elasticsearch进行模糊查询--转载
    springboot集成elasticsearch7.6.1,常用api调用,创建,查找,删除索引,crud,高亮。。。--转载
    SpringBoot整合Elasticsearch7.2.0的实现方法-转载
    Spring Webflux 入门 -转载
    java 视频流截屏,形成缩略图
    记录一下 spring boot 线程处理返回数据
  • 原文地址:https://www.cnblogs.com/yinkw/p/apue_orphaned_process_groups.html
Copyright © 2020-2023  润新知