我刚刚做了一个演讲,总结为:
收获
由父级对终止的子级执行(使用wait或waitpid)
为父级提供退出状态信息
内核然后删除僵尸子进程
因此,我了解通过在父进程中调用wait
或waitpid
来进行收割,然后内核删除了僵尸进程。如果确实是这种情况,那么只有在调用wait
或waitpid
时才进行收割,为什么子进程在返回theor入口函数后实际上消失了-我的意思是确实确实好像子进程已被收获,因此即使父进程可能没有在等待,也不会浪费资源。
“收割”仅在调用wait
或waitpid
时才可能吗?只要进程返回并退出其入口函数(我假设所有进程都这样做),它们是否就“收获”了?谈论“收获”好像有什么特殊的意义是什么?
答案 0 :(得分:2)
子进程退出时不能完全“消失”。它不再作为正在运行的进程而存在,并且它的大部分/所有资源(内存,打开的文件等)都已释放,但是它仍然保留在进程表中。它保留在进程表中,因为这是存储其退出状态的地方,以便父级可以通过调用wait
变体之一来检索它。如果父项未能调用wait
,则进程表条目会停留在周围-这就是使它成为“僵尸”的原因。
我说过,它的大部分/所有资源都已释放,但是肯定仍在使用的一种资源是进程表插槽。
只要(死)孩子的父母存在,内核就不会知道父母最终不会调用wait
,因此进程表插槽必须留在那儿,最终调用wait
(如果有)可以返回正确的退出状态。
如果父级最终退出(从未调用wait
),则子级将由祖父母继承,这通常是像shell或init
这样的“主”进程,该进程通常会执行致电wait
,这将最终“收获”可怜的年轻僵尸。
所以,是的,正如您的演讲所述,父母正确“收获”孩子的唯一方法是调用wait
函数之一。 (或者退出,但是如果父母要长时间奔跑,那就太糟糕了。)
答案 1 :(得分:2)
wait*()
调用的目的是允许子进程将状态报告回父进程。当子进程退出时,操作系统将状态数据保存在一个小数据结构中,直到父进程读取它为止。从这个意义上说,收割正在清除少量的数据结构。
如果父母不关心等待孩子的状态,则可以以允许父母忽略状态的方式编写代码,因此收割是半自动进行的。一种方法是忽略SIGCHLD
信号。
另一种方法是执行双叉创建孙子进程。这样做时,“父母”会在调用wait()
之后进行阻塞fork()
。然后,子级执行另一个fork()
来创建孙级,然后立即退出,从而使父级解除阻止。现在,孙子完成了真正的工作,并被init
进程自动收割。