1、孤儿进
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作
为了释放子进程的占用的系统资源: 进程结束之后,能够释放用户区空间 ,释放不了PCB,必须由父进程释放
2、僵尸进程
一个进程使用 fork 创建子进程,
如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称之为僵死进程。
3、进程回收
3.1wait 阻塞函数
函数作用:
1.
阻塞并等待子进程退出
2.
回收子进程残留资源
3.
获取子进程结束状态(退出原因)
pid_t wait(int *wstatus);
返回值:
‐1 :
回收失败,已经没有子进程了
>0 :
回收子进程对应的
pid
参数 :
status
判断子进程如何退出状态
1.WIFEXITED(status):
为非
0
,进程正常结束
WEXITSTATUS(status) :如上宏为真,使用此宏,获取进程退出状态的参数
2.WIFSIGNALED(status):
为非
0
,进程异常退出
WTERMSIG(status): 如上宏为真,使用此宏,取得使进程种植的那个信号的编号
调用一次只能回收一个子进程
3.1.1父进程正常回收子进程:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
int i = 0;
pid_t zipid;
int status;
if(pid < 0)
{
printf("fork 错误\n");
}
if(pid < 0)
{
printf("fork 错误\n");
}
else if(pid > 0)
{
printf("这是父进程pid=%d\n",getpid());
zipid = wait(&status);
if(zipid == -1)
{
printf("回收失败已经没有子进程了\n");
}
if(zipid > 0)
{
printf("回收子进程的PID是%d\n",zipid);
}
if(WIFEXITED(status) != 0)
{
printf("子进程正常结束,进程参数信息=%d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status) != 0)
{
printf("子进程异常推出,错误进程参数信息=%d\n",WTERMSIG(status));
}
}
else if(pid == 0)
{
printf("这是一个子进程,子进程pid=%d,父进程ppid =%d\n",getpid(),getppid());
}
for(i = 0;i < 4;i++)
printf("i = %d\n",i);
return 0;
}
运行结果:
3.1.2异常退出:这里采用强制杀死子进程的例子
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
int i = 0;
pid_t zipid;
int status;
if(pid < 0)
{
printf("fork 错误\n");
}
else if(pid > 0)
{
printf("这是父进程pid=%d\n",getpid());
zipid = wait(&status);
if(zipid == -1)
{
printf("回收失败已经没有子进程了\n");
}
if(zipid > 0)
{
printf("回收子进程的PID是%d\n",zipid);
}
if(WIFEXITED(status) != 0)
{
printf("子进程正常结束,进程参数信息=%d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status) != 0)
{
printf("子进程异常推出,错误进程参数信息=%d\n",WTERMSIG(status));
}
}
else if(pid == 0)
{
while(1)
{
sleep(1);
printf("这是一个子进程,子进程pid=%d,父进程ppid =%d\n",getpid(),getppid());
}
}
for(i = 0;i < 4;i++)
printf("i = %d\n",i);
return 0;
}
运行结果:
3.2waitpid函数
函数作用:同wait函数
pid_t waitpid(pid_t pid, int *status, int options);
参数:
1.pid:
指定回收某个子进程
pid == ‐1 回收所有子进程:while( (wpid=waitpid(‐1,status,0)) != ‐1)
ps:每次调用只会回收一个子进程,所以要不断的调用才可以回收所有字进程
pid > 0
回收某个
pid
相等的子进程
pid == 0
回收当前进程组的任一子进程
pid < 0
子进程的
PID
取反(加减号)
2.status:
子进程的退出状态,
用法同wait函数
3.options:
设置为
WNOHANG,
函数非阻塞,设置为
0
,函数阻塞
返回值:
>0 :
返回清理掉的子进程
ID
‐1
:回收失败,无子进程
如果为非阻塞(参数
3
为
WNOHANG == 0)
=0
:参数
3
为
WNOHANG,
且子进程正在运行
阻塞状态:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
int i = 0;
pid_t zipid;
int status;
if(pid < 0)
{
printf("fork 错误\n");
}
else if(pid > 0)
{
printf("这是父进程pid=%d\n",getpid());
while( (zipid=waitpid(-1,&status,0)) != -1)//用阻塞的方式回收所有子进程
{
if(zipid == -1)
{
printf("回收失败已经没有子进程了\n");
}
if(zipid > 0)
{
printf("回收子进程的PID是%d\n",zipid);
}
if(WIFEXITED(status) != 0)
{
printf("子进程正常结束,进程参数信息=%d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status) != 0)
{
printf("子进程异常推出,错误进程参数信息=%d\n",WTERMSIG(status));
}
}
}
else if(pid == 0)
{
printf("这是一个子进程,子进程pid=%d,父进程ppid =%d\n",getpid(),getppid());
}
for(i = 0;i < 4;i++)
printf("i = %d\n",i);
return 0;
}
运行结果:
ps:先执行子进程的程序,再执行父进程的程序
非阻塞状态:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
int i = 0;
pid_t zipid;
int status;
if(pid < 0)
{
printf("fork 错误\n");
}
else if(pid > 0)
{
printf("这是父进程pid=%d\n",getpid());
while( (zipid=waitpid(-1,&status,WNOHANG)) != -1)//用不阻塞的方式回收所有子进程
{
if(zipid == 0)//子进程正在运行
{
continue;
}
if(zipid == -1)
{
printf("回收失败已经没有子进程了\n");
}
if(zipid > 0)
{
printf("回收子进程的PID是%d\n",zipid);
}
if(WIFEXITED(status) != 0)
{
printf("子进程正常结束,进程参数信息=%d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status) != 0)
{
printf("子进程异常推出,错误进程参数信息=%d\n",WTERMSIG(status));
}
}
}
else if(pid == 0)
{
printf("这是一个子进程,子进程pid=%d,父进程ppid =%d\n",getpid(),getppid());
}
for(i = 0;i < 4;i++)
printf("i = %d\n",i);
return 0;
}
运行结果: