文章目录
- 进程控制(二)
- 进程等待
- wait函数
- waitpid函数
- wait/waitpid获取子进程状态码的过程
- 进程等待相关的宏
- 总结
进程控制(二)
延续对于上文进程结束,我们继续对于进程控制进行学习,本文我们主要是对于进程等待进行学习,进程等待,我们在前文初步接触进程的时候,我们知道,进程等待是指我们在运行该进程的时候,在等待资源,当有了资源分配后,便可以运行该进程,在本文中,我们认识的进程等待是指,子进程退出时,先进入僵尸状态,然后父进程进行等待(wait/waitpid)来获取子进程退出信息,这个过程叫做进程等待。
进程等待
进程等待,是子进程退出信息被父进程接收时,父进程处于等待状态的一种描述。
进程等待是指通过系统调用wait/waitpid,来进行对子进程进行状态检测与回收的功能。
- 子进程退出时,如果父进程没有接收信息,那么会导致僵尸进程的问题,造成内存泄漏,所以父进程必须通过进程等待来回收子进程退出信息。(必要)
- 通过回收子进程的退出信息,也可以知道子进程退出码,以及是否出现异常,status。(可选)
所以,我们必须要实现进程等待,防止内存泄漏,对于得到的子进程退出信息,我们可以选择性的利用,可有可无,看自己需求。
wait函数
wait函数,可以实现进程等待,只有一个参数,status,输出型参数,可以获得子进程退出信息
wait函数在2号手册上,头文件也可以表明,wait函数以及waitpid函数是系统调用接口,通过该函数来访问操作系统,使得操作系统对于子进程进行回收处理。
core dump,以后会用到,现在不需要掌握,只需要知道,这是用来进行调试的。
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#define N 10
void RunChild()
{
int cnt=5;
while(cnt)
{
printf("Child pid: %d, parent pid: %d\n",getpid(),getppid());//获取pid和ppid
sleep(1);
cnt--;
}
//printf("Child pid: %d, parent pid: %d\n",getpid(),getppid());//获取pid和ppid
//sleep(15);
}
int main()
{
//实现创建子进程,并对于子进程进行等待
for(int i=0;i<N;i++)
{
pid_t id=fork();//创建子进程
if(id==0)
{
RunChild();
exit(i);//退出码
}
//父进程执行下面信息
printf("create Child proc : %d success\n",id);
}
sleep(10);
return 0;
}
上述代码,我们并没有是wait,会造成内存泄漏,下面我们来通过父进程来接收子进程的退出信息。
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#define N 10
void RunChild()
{
int cnt=5;
while(cnt)
{
printf("Child pid: %d, parent pid: %d\n",getpid(),getppid());//获取pid和ppid
sleep(1);
cnt--;
}
//printf("Child pid: %d, parent pid: %d\n",getpid(),getppid());//获取pid和ppid
//sleep(15);
}
int main()
{
//实现创建子进程,并对于子进程进行等待
for(int i=0;i<N;i++)
{
pid_t id=fork();//创建子进程
if(id==0)
{
RunChild();
exit(i);//退出码
}
//父进程执行下面信息
//wait;进程等待
printf("create Child proc : %d success\n",id);
}
//进程等待
for(int i=0;i<N;i++)
{
//会实现进程的等待
pid_t id=wait(NULL);//wait等待是随机的,等待还没有被接收信息的子进程,有几个子进程就需要等几次。
//int status=0;
//pid_t id=wait(&status);//传地址,操作系统来进行存储子进程退出信息
if(id>0)
{
//printf("wait %d success\n ; exit sig: %d\n",id,WEXITSTATUS(status));
printf("wait %d success\n",id);
}
}
return 0;
}
waitpid函数
waitpid函数,其拥有三个参数,功能相较于wait更多,可以认为waitpid可以包含wait的功能,wait的功能比较单一,智能获取状态码status,而且是随机等待子进程。
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int* status, int options);
参数介绍
返回值pid_t:
- 大于0,表示等待子进程成功,返回值是子进程的pid
- 小于0,表示等待子进程失败
- 等于0,表示等待条件还没有就绪,此时父进程可以做自己的事情
pid参数:
- 大于0,表示等待指定的子进程
- pid = -1 ,表示等待随机子进程
status参数:
- NULL,表示不需要子进程的状态码
- 反之,作为输出型参数,操作系统将子进程退出信息写入status中
options参数:
- 0,表示阻塞等待
- WNOHONG,表示非阻塞等待
wait/waitpid获取子进程状态码的过程
wait和waitpid都是系统调用,为什么要通过系统调用函数,而不是库函数来实现该功能,这是因为,由于进程具有独立性,相互不影响,所以一般的函数无法访问到另一进程的内容,而系统调用,可以在全局上(操作系统的角度)来找到子进程PCB,得到状态码
等待流程
- 子进程运行完毕后,进入僵尸状态(Z),将退出码信息存储到子进程PCB中(exit_code,exit_signal),释放代码,以及数据,保留task_struct结构体信息。
- 父进程通过wait/waitpid,通过系统调用,得到子进程PCB中的退出信息,将推出信息,以位图的方式,写入到int类型的status参数,从而父进程得到子进程的推出信息。
exit_code:表示退出码
exit_signal:表示结束信号,也就是判断是否异常,如果为0,表示正常,如果非零,那就是接收了终止信号 kill -num,其中num==exit_signal
实现方式:
exit_signal == status&0x7F == WIFEXITED(status)
exit_code == status>>8&0xFF == WEXITSTATUS(status)
进程等待相关的宏
WEXITSTATUS(status):表示输出退出码(exit_code)
WNOHONG:表示非阻塞等待,用于waitpid的option参数。
WIFEXITED(status):通过状态码,表示子进程是否正常结束(是否异常),如果正常,返回ture
总结
进程等待,是父进程必须要完成的事情,是为了防止内存泄漏,也是为了知道子进程完成任务情况(由状态码得出结论),主要是了解wait/waitpid函数,以及status参数的构成,为什么能表示进程的三种退出情况,以及waitpid函数的非阻塞等待宏WNOHONG,还有退出码WEXITSTATUS,还有判断子进程是否正常退出的宏命令WIFEXITED。