wait和waitpid
我们知道,在Linux系统中,fork是创建子进程的唯一方法,但是一旦创建的子进程终止,那么又怎样回收呢?
其实,在Linux中,终止的子进程会给父进程发送一个SIGCHLD信号,来表示自己已终止。同时,子进程的pid和其他状态信息会存放在系统的表项中,如果父进程不做任何处理,子进程出于僵死状态(Z),这个表项会一直占用,且该表项系统资源有限,这样明显不好。父进程对其的处理就是取得该子进程的信息,然后系统释放表项中信息。
wait 和 waitpid 就表示父进程获取表项信息,释放子进程。
#include <sys/wait.h> pid_t wait(int *statloc); pid_t waitpid(pid_t pid, int statloc, int options); 均返回:成功为进程ID,出错为0或-1;statloc表子进程终止状态
wait:如果调用该函数的进程没有已终止子进程,不过有一个或多个子进程正在执行,则阻塞到现有子进程第一个终止为止;
waitpid:pid可指定等待的终止子进程,options可设置WNOHANG表示不阻塞。
《unix网络编程卷一》中有一个例子P109,讲述通过信号处理函数调用wait和waitpid以处理僵死进程。一个父进程的多个子进程同时终止,那么会有多个SIGCHLD信号几乎同时传递给父进程。信号处理函数执行,阻塞调用wait,在阻塞期间可能有多个信号到达,但是wait阻塞返回后,那些信号只留下一个,则再次调用信号处理函数。对于有丢失信号,会有清理僵死进程不完全的状况,因为在信号处理期间其他到达的信号会因为相同而被丢弃只剩下一个,也就表示触发信号处理函数的次数少了,自然清理不干净。
但是通过非阻塞循环调用waitpid却可以完全清理,先说,在其他阻塞期间同时来的信号还是会被丢失,但是无所谓,因为一旦有信号触发到信号处理函数里面,循环waitpid可以清理掉当时已经终止的所有子进程,所以并不需要每一个信号来驱动信号处理函数,所以他总是会被清除干净的。而前面的wait是不循环的,因为它是阻塞的,一旦循环那就…
这一段内容只看书很难理解,可以参考:http://bbs.chinaunix.net/thread-828942-1-1.html
再来说说僵死进程和孤儿进程
僵死进程:如前所述,子进程终止,父进程却没有清理掉它,导致它的pid和状态信息还存留在系统相关进程表项中,占用资源。
孤儿进程:父进程终止了,子进程还正常运行。因为这些子进程将来终止的时候需要父进程wait呀,可是父进程已经就终止了,怎么办。其实当父进程终止的时候,子进程的父进程id会置为1,即成为init进程的子进程,将来终止的话,由init进程处理回收它。