我知道没有强制父进程等待其所有子进程终止。然而,这是遵循的惯例。此外,我知道如果父进程在子进程终止之前终止,那么子进程将成为孤儿进程,并且将被在里面过程。但我不明白的是,如果子进程成为孤儿进程并被子进程收养,会有什么问题?在里面过程。为什么它应该附加到父进程本身直到它终止?
答案1
这种约定的主要原因是,如果一个进程分叉子进程,通常子进程正在执行主进程预计要做的部分工作。 您是否有任何考虑分叉的程序示例?
这里有些例子:
- 进行密集计算的程序可能会分叉自身的多个副本,以便同时在多个 CPU/核心上运行。 (为此使用线程可能更传统,但当然可以通过分叉进程来完成。)这样的程序可能被设计为每个进程只写一个独立的输出。但主进程等待所有子进程完成然后合并他们的结果也是很常见的。
- 像这样的程序
netcat
有时有一个进程从主机 A 读取并向主机 B 写入,另一个进程从主机 B 读取并向主机 A 写入。(是的,这也可以通过线程来完成。) find -exec
简而言之,在和的情况下xargs
,(主)程序的工作是运行从属程序 并等待它完成。 想象一下如果用户说会发生什么寻找 。 -type f -exec cp {} /备份 ';' && rm -r .
并find
退出,无需等待所有副本完成。
在这些情况(以及其他情况)下,直到所有子进程完成后,主程序的工作才完成。因此,程序在等待所有子进程之前不得退出。
当然这不是 fork 的唯一使用方式。网络服务器(例如,FTP 和邮件)通常有一个主进程来侦听传入连接,然后在每次获得客户端连接时派生一个子进程。此类子进程可以在任意时间终止(由客户端确定),并且主进程没有理由等待其子进程。
关于子进程终止时与哪个“父”/收割者进程关联的信息并不是真正的问题。
答案2
这种约定的主要原因是,如果父进程在子进程之前终止,则子进程的退出代码将丢失,并且子进程可能会在一段时间内保持僵尸状态。
子进程终止后,它将保留(并消耗内存),直到读取退出代码。这就是所谓的僵尸进程——死亡,但未收获(移除)。
通常,父进程有责任读取退出代码并允许僵尸进程完全消失。由于父母应该跟踪孩子,因此希望能很快清理干净。如果父进程不这样做,就会出现资源泄漏。
如果父进程在子进程之前终止,init 确实会接管该责任,但它可能不会立即意识到这一点,因此子进程可能会保持僵尸状态更长时间,从而占用更多资源。
编辑:为了澄清,处于僵尸状态的进程不会保留其所有内存 - 大部分内存在进程成为僵尸之前被释放。它是进程表中保留的条目。进程表条目越多,内核执行与进程相关的活动所需的时间就越多。