子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束,于是就产生了孤儿进程和僵尸进程。
1. 孤儿进程
孤儿进程指一个父进程退出后它的子进程还在运行,那么子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程完成状态收集工作,init进程会周期地wait()它的已经退出的子进程,因此孤儿进程不会造成什么危害。
2. 僵尸进程
为了防止子进程结束时丢失其状态信息,unix采用一种机制可以保证只要父进程想知道子进程结束时的信息,它就可以得到:在每个进程退出时,内核释放该进程所有的资源,包括打开的文件,占用的内存,但是仍然保留一些信息(如PID进程号、退出状态、运行时间等),这些保留的信息直到进程通过调用wait/waitpid时才会释放。
这样也导致了一个问题:如果父进程没有调用wait/waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称为僵尸进程。如果产生大量的僵尸进程,将导致系统没有可用的进程号而不能创建进程。
wait函数
进程一旦调用wait函数,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果找到这样一个已经变成僵尸进程的子进程,wait就会收集这个子进程的信息,并把它销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
wait()函数原型:
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int* status);
wait会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。
wait()函数的返回值为子进程的进程标识符,而函数参数中的status也会被修改为子进程的结束状态值,后续可以通过对这个status的读取获得更多信息(如下面代码中的两个宏)。如果不需要结束状态值,可以把status设置为NULL。
代码分析:
《后台开发:核心技术与应用实践》Page_345:例10.7“利用WEXITSTATUS获得子进程的返回码 ”
#include<sys/types.h>
#include<sys/wait.h>
#include<unisted.h>
#include<stdlib.h>
#include<stdio.h>
int main()
{
pid_t pid = fork(); //fork一个子进程
if (pid < 0)
{
perror("fork error\n");
return 0;
}
else if (pid ></