子进程在父进程调用fork后生成的,如果父进程在子进程之前终止,那么子进程的父进程将改变为init进程。我们称这些进程由init进程收养。
在一个进程终止时,内核会逐个检查所有活动进程,如果发现它是正要结束进程的子进程,则将该进程的父进程更改为init,这样就保证了每个进程都有一个父进程。
那么如果孤儿进程终止会不会成为僵死进程呢?
不会,因为init的子进程结束后,init就会调用一个wait函数取得其终止状态,这样就防止系统中塞满僵死进程。
内核为每个终止的子进程保存一定量的信息(PCB),所以,当终止进程的父进程调用wait或waitpid时,可以得到这些信息。
在UNIX中,一个已经终止、但是其父进程尚未对其进行善后处理的进程被称为僵死进程。(子进程的残留资源(pcb)存放在内核中)
ps会将僵死进程状态打印为Z.(通过ps命令查看)
僵死进程是不能通过kill清除的,kill是终止进程,而僵死进程已经终止。
当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。父进程可以选择忽略该信号,或者提供一个信号处理程序,对于这种信号系统默认动作是忽略它。
#include
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int option);
执行成功返回进程ID,失败返回0或-1
功能:
进程如果是正常终止,PCB中保存着退出状态,如果是异常终止则保存着该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。
例:子进程回收
#include
#include
#include
#include
int main(){
pid_t pid,wpid;
pid=fork();
int status;
if(pid<0){
perror("fork error");
exit(-1);
}
else if(pid==0){
printf("i am child\n");
sleep(60);//此处睡眠60s是为了有足够的时间去发送信号,让进程异常终止
return 0;
}
else{
wpid=wait(&status);
if(wpid==-1){
perror("wait error");
exit(-1);
}
if(WIFEXITED(status)){
printf("%d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status)){
printf("%d\n",WTERMSIG(status));
}
sleep(2);
printf("parent end\n");
}
}
终止状态用定义在
WIFEXITED(status):若为正常终止子进程,则为真。可以执行WEXITSTATUS(status),获取子进程传递给exit或_exit参数的低8位
WIFSIGNALED(status):若为异常终止子进程,则为真。可以执行WTERMSIG(status),获取使子进程终止的信号编号
WIFSTOPPED(status):若为当前暂停子进程的返回的状态,则为真。可以执行WTERMSIG,获取使子进程暂停的信号编号
WIFCONTINUED(status):若在暂停后已经继续运行的子进程返回的状态,则为真。
waitpid函数: pid_t waitpid(pid_t pid,int *status,int option);
pid==-1 表示等待任一子进程。此时与wait相同
pid>0 表示等待进程ID与pid相等的子进程
pid==0 表示等待组ID等于调用进程组ID的任一子进程
pid<-1 表示等待组ID等于pid绝对值的任一子进程
option 值为WNOCHANG 表示若指定的子进程不是立即可用的,则waitpid不阻塞,此时其返回值为0