收获 children 意味着什么?

What does reaping children imply?

我刚刚有一个讲座总结收获为:

收割

所以我理解收割是通过从parent进程调用waitwaitpid完成的,之后内核删除僵尸进程。如果确实如此,那么只有在调用 waitwaitpid 时才会进行收割,为什么 child 进程实际上在 returning 之后在入口函数中消失了 -我的意思是,确实看起来好像 child 进程已经被收割,因此即使 parent 进程可能没有等待,也没有资源被浪费。

那么"reaping"是不是只有在调用wait或者waitpid的时候才有可能呢?进程是否 "reaped" 只要它们 return 并退出它们的入口函数(我假设所有进程都这样做) - 谈论 "reaping" 就好像它是特殊的东西有什么意义?

child 进程在退出时没有完全“消失”。它不再作为 运行 进程存在,并且其 most/all 的资源(内存、打开的文件等)被释放, 它仍然保留在进程 table。它保留在进程 table 中,因为这是存储其退出状态的地方,因此 parent 可以通过调用 wait 变体之一来检索它。如果 parent 调用 wait 失败,进程 table 条目会保留下来——这就是它成为“僵尸”的原因。

我说它的 most/all 资源被释放了,但肯定还在消耗的一个资源是进程 table 槽。

只要(死)child 的 parent 存在,内核就不知道 parent 不会调用 wait最终,进程 table 槽必须留在那里,以便最终调用 wait(如果有的话)可以 return 正确的退出状态。

如果 parent 最终退出(从未调用 wait),child 将由 grandparent 继承,后者通常是“master”像 shell 或 init 这样的过程会定期调用 wait 并且最终会“收获”可怜的年轻僵尸。

所以,是的,parent 正确“收获”child 的唯一方法确实是,就像您在演讲中所说的那样,调用其中一个wait 个函数。 (或者退出,但如果 parent 是 long-running,那不是一个选项。)

脚注:我说“child 将由 grandparent 继承”,但我认为我错了。在 Unix 和 Linux 下,孤立进程通常总是由 pid 1 继承,又名 init.

wait*() 调用的目的是允许 child 进程将状态报告回 parent 进程。当 child 进程退出时,操作系统将状态数据保存在一个小数据结构中,直到 parent 读取它。 从这个意义上说,收割 正在清理那个小数据结构。

如果 parent 不关心等待来自 child 的状态,代码可以以允许 parent 忽略状态的方式编写,等等收获发生 semi-automatically。一种方法是忽略 SIGCHLD 信号。

另一种方法是执行 double-fork 来创建一个 grandchild 进程。执行此操作时,"parent" 在调用 fork() 后执行阻塞 wait()。然后,child 执行另一个 fork() 来创建 grandchild 然后立即退出,导致 parent 解锁。 grandchild 现在做真正的工作,并由 init 进程自动收割。