下面的代码,可以看到父进程执行10次,子进程执行3次。
我们将程序挂在后台运行,当子进程运行结束后,我们运行ps查看进程,可以看到,子进程好像仍然存在。
进程总归是要终结的。当一个进程终结时,内核必须释放它所占有的资源,并把这一事件,告知其父进程。但是系统为了在子进程终结后仍能获得它的信息,所以进程保留了它的进程描述符(即PCB),所以这种情况的进程叫做僵死进程。
现在有以下方法可以处理僵死进程(可能不完整,我仍在补充)
方法一:父进程先于子进程退出。(可以但不实用)
我们更改程序代码,使父进程打印3次,子进程打印8次,子进程先于父进程退出。
可以看到,父进程和子进程都没有进入僵死状态,已经达到了基本目标。
所以我们只需要父进程先于子进程结束,如让父进程运行时间短,先kill掉父进程,等等。
但是我们也发现了子进程的父进程(ppid)发生了变化,这种失去了原有父进程的子进程称为孤儿进程。
如果父进程在子进程之前退出,必须有机制来保证子进程能找到一个新的父亲,否则这些称为孤儿的进程就会在退出时永远处于僵死状态,白白耗费内存。对于这个问题,解决方法是给子进程找一个进程当做父亲,如果不行,就让init做他们的父进程。这样在子进程结束的时候,就不会称为僵死进程。
但是很明显这种方法太过强硬,有点杀鸡取卵的味道,不是很好的解决方法。
方法二:调用wait()函数(无法达成并发执行)
我们在程序代码中直接加入wait()。
运行程序可以看到先执行了子程序,当子程序结束之后,父程序才开始执行。
wait()函数的标准动作是刮起调用它的进程,直到其中的一个子进程退出,此时函数会返回该子进程的PID。
这样父进程就获取了子进程的信息,子进程就不会成为僵死进程,但是父进程会等待,无法达成并发。
方法三:获取子进程的信号。
获取子进程结束后的信号,并进行wait()处理。
运行结果如下图:
可以看到在子进程结束了之后,并没有产生僵死进程,因为我们对信号进行了处理。