收获 children 意味着什么?
What does reaping children imply?
我刚刚有一个讲座总结收获为:
收割
由 parent 在终止时执行 child(使用 wait 或 waitpid)
Parent 给出退出状态信息
内核然后删除僵尸child进程
所以我理解收割是通过从parent进程调用wait
或waitpid
完成的,之后内核删除僵尸进程。如果确实如此,那么只有在调用 wait
或 waitpid
时才会进行收割,为什么 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
进程自动收割。
我刚刚有一个讲座总结收获为:
收割
由 parent 在终止时执行 child(使用 wait 或 waitpid)
Parent 给出退出状态信息
内核然后删除僵尸child进程
所以我理解收割是通过从parent进程调用wait
或waitpid
完成的,之后内核删除僵尸进程。如果确实如此,那么只有在调用 wait
或 waitpid
时才会进行收割,为什么 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
进程自动收割。