僵死进程
1、产生原因
进程主体结束,但是其 PCB 没有释放
PCB 中记录进程的运行信息,进程结束时,PCB 中有一个 exit_code,保存进程的退出信息,进程退出信息如果没有被(父进程)处理,则 PCB 无法释放
子进程结束,父进程未结束并且父进程未获取(处理)子进程的退出状态,从而子进程不得不保存退出码,所以整个 PCB 就无法释放
父进程可以获取子进程的退出码
int main()
{
pid_t pid=fork();
assert(pid!=-1);
int n=0;
char *s=NULL;
//子进程
if(pid==0)
{
n=0;
s="child pid";
}
//父进程
else
{
n=5;
s="---father----";
/*
while(1)
{
sleep(2);
printf("---father----\n");
printf("father pid=%d,ppid=%d\n",getpid(),getppid());
}*/
}
int i=0;
for(;i<n;i++)
{
printf("%s,%d,father pid=%d,ppid=%d\n",s,i,getpid(),getppid());
sleep(2);
}
return 0;
}
查找僵尸进程
ps aux|grep defunct
父进程如何处理子进程的退出状态:
用 wait 函数将调用者阻塞,直到某个子进程终结,故父进程可调用 wait 函数回收其僵尸子进程。
阻塞运行:函数调用,只要条件不满足,则函数不成立
非阻塞运行:函数调用,无论任何情况,函数都会立即返回
1、wait
pid_t wait( int *reval); 阻塞
调用一次,只能处理一个子进程的僵死状态
wait 函数会阻塞,直到任意一个子进程结束
返回值:-1,回收失败,已经没有子进程了
>0,回收是子进程对应的 pid
reval:获取到子进程的退出码
void fun(int sign)
{
pid_t pid=wait(NULL);
printf("pid=%d\n",pid);
}
int main()
{
signal(SIGCHLD,fun);
pid_t n=fork();
assert(n!=-1);
if(n==0)
{
printf("child start:%d\n",getpid());
sleep(2);
printf("chile over\n");
}
else
{
printf("father start:\n");
while(1)
{
sleep(1);
printf("father running\n");
}
sleep(100);
printf("father over\n");
}
}
2、waitpid
如果在调用 waitpid() 函数时,当指定等待的子进程已经停止运行或结束了,则 waitpid() 会立即返回;但是如果子进程还没有停止运行或结束,则调用 waitpid() 函数的父进程则会被阻塞,暂停运行。
pid_t waitpid( pid_t pid, int *reval, int flag); 非阻塞
pid:
pid > 0 某个子进程的 pid
pid == -1 回收所有的子进程
循环回收
while((wpid = waitpid(-1, &status, WNOHANG)));
pid == 0 回收当前进程组所有的子进程
pid < 0 子进程的 pid 取反(加减号)
flag
0 阻塞
WNOHANG 非阻塞
返回值:
-1 回收失败
>0 回收子进程的 pid
如果为非阻塞 =0:子进程处于运行状态