V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
ashiamd
V2EX  ›  问与答

萌新请问下, Linux 中是子进程 exit()中的_exit()触发中断进而要求内核 kenerl 发送 SIGCHLD 给父进程吗?

  •  
  •   ashiamd · 2020-08-13 02:45:34 +08:00 · 1746 次点击
    这是一个创建于 1598 天前的主题,其中的信息可能已经有所发展或是发生改变。

    查阅了几个小时关于 SIGCHLD 和 exit()相关的文章、Linux 守护进程 daemon 相关的文章之后。 现在有个疑惑。就是 SIGCHLD 到底是谁发出的?进而如果需要无视该信号,那么 signal(SIGCHLD,SIG_IGN)是要写在父进程中,还是被新建的 daemon 进程中??

    这方面不太了解,网上查了 7-10 篇文章,感觉可能我语文阅读能力有问题?总感觉没有人说清楚这个 SIGCHLD 到底到底是哪里出现,最后又会被谁接收?

    9 条回复    2020-08-17 11:17:21 +08:00
    ashiamd
        1
    ashiamd  
    OP
       2020-08-13 02:49:19 +08:00
    附上几篇看到的文章中比较标志性的,比如[创建守护进程为什么要 fork 两次]( https://blog.csdn.net/dream_1996/article/details/73467969)下方 "(6)其他:忽略 SIGCHLD 信号"的代码,我不是很懂为为什么是需要在新建出来的 daemon 进程执行 signal(SIGCHLD,SIG_IGN),这个 SIGCHLD 不应该是内核发送给父进程的吗?为什么反而是在子进程中声明无视 SIGCHLD ??
    ashiamd
        2
    ashiamd  
    OP
       2020-08-13 02:50:27 +08:00
    附上几篇看到的文章中比较标志性的。
    比如[创建守护进程为什么要 fork 两次]( https://blog.csdn.net/dream_1996/article/details/73467969)

    "(6)其他:忽略 SIGCHLD 信号"的代码,我不是很懂为为什么是需要在新建出来的 daemon 进程执行 signal(SIGCHLD,SIG_IGN)。
    这个 SIGCHLD 不应该是内核发送给父进程的吗?为什么反而是在子进程中声明无视 SIGCHLD ??
    Nitroethane
        3
    Nitroethane  
       2020-08-13 07:57:48 +08:00 via iPhone   ❤️ 1
    当一个进程得子进程退出时,其父进程会收到 SIGCHLD 信号。调用 signal(SIGCHLD, SIG_IGN) 的目的是避免在父进程提前退出的情况下,子进程退出时不会变成 zombie 。
    至于你说的那篇文章中调用 signal 函数,应该跟创建 daemon 进程没多大关系
    feather12315
        4
    feather12315  
       2020-08-13 08:39:26 +08:00 via Android   ❤️ 1
    Q1:SIGCHLD 是子进程在进行 exit 系统调用的时候,在子进程的执行逻辑中子进程向父进程的 PCB 中添加的一个标志。有专门的函数进行这一逻辑。

    Q2:SIGHUB 在执行 exit 系统调用的过程中出现,被父进程接收。比如三个进程,1 是 2 的子进程,2 是 3 的子进程,当 2 退出后,1 号的父进程变为 3,1 号的 SIGCHLD 发送给 3 号。
    ashiamd
        5
    ashiamd  
    OP
       2020-08-13 17:34:09 +08:00
    @feather12315
    @Nitroethane
    昨晚深夜 找了不少 google 上的 wiki 什么的,好像也比较直观的说法。下午又下载 glib-c 的 C 代码,可惜没怎么看懂。

    然后刚才看到一篇对 SIGCHLD 有代码示例的文章 ==>[ [Linux]关于 SIGCHLD ]( https://blog.csdn.net/xxpresent/article/details/73028750)

    我按着里面的代码,在 Linux 服务器上,移动了 `signal(SIGCHLD,myhandler);` 这一句的位置;写几份 C 代码运行看效果

    (1 )没移动,按文章那样,应该 父 /子进程 都等于 受到了这句函数最后导致的 PCB 变化等影响。有输出 sig
    (2 ) 移动到`if( id == 0)` 条件语句块里,子进程范围, 没有输出 sig
    (3) 移动到 `else` 条件语句块里,原进程(父进程)范围,有输出 sig 。

    -------------------------------
    以上,结合我之前所学。我认为 SIGCHLD,是 exit()中的_exit()像操作系统 注册了 SIGCHLD 的 handler,要求当前进程执行 exit()内的逻辑时,要求内核向父进程通知 SIGCHLD 。而操作系统内部默认对 SIGCHLD 采取动作为忽略==>这个我认为是指 C 库代码里有对一些 SIG 系列信号预设了处理函数 handler,其中如果一个进程收到 SIGCHLD 信号,那么默认触发 C 库里面自动忽略 该信号的逻辑。==> 也就是 除非 父进程主动写 signal(SIGCHLD,自定义 handler 函数),来处理子进程 C 库代码预设的 exit()逻辑中要求内核向父进程发送的 SIGCHLD 信号;否则父进程其实收到 SIGCHLD 就直接调用 C 库里逻辑,忽略 SIGCHLD 信号了。

    不知道这样说对不对?
    julyclyde
        6
    julyclyde  
       2020-08-14 23:56:41 +08:00 via iPad   ❤️ 1
    信号从概念上并不重视谁发出的啊
    julyclyde
        7
    julyclyde  
       2020-08-14 23:58:25 +08:00 via iPad
    子进程无视 child 信号,主要是为了清除从父进程继承过来的 handler 避免副作用吧?
    ashiamd
        8
    ashiamd  
    OP
       2020-08-15 00:40:56 +08:00
    @julyclyde 谢谢老哥回答。
    是不是意思说,为了保险起见(因为有时候无法确定父进程是否有自定义处理 SIGCHLD 信号的 handler ),所以才在子进程中执行 signal(SIGCHLD,SIG_IGN)。
    即,保证不管父进程之前如何,至少新建的这个子进程,对 SIGCHLD 信号量一定是采取"忽略“的操作。
    julyclyde
        9
    julyclyde  
       2020-08-17 11:17:21 +08:00   ❤️ 1
    @ashiamd 不是一定忽略,是一定不要继承,而要明确设置自己的行为
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1165 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:22 · PVG 02:22 · LAX 10:22 · JFK 13:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.