一、进程等待意义
当父进程创建子进程之后,当子进程退出时,需要它的父进程回收它的内核数据结构对象(pcb),因为进程退出之后不回收它会造成内存泄漏问题,子进程退出,若是父进程不管,那么子进程就会一直是僵尸状态,而成为僵尸进程,会造成内存泄漏!进而进程一旦变成了僵尸状态,那么不会收到信号,那么也不会被杀死,可以说是刀枪不入。而且父进程创建子进程就是让子进程去执行不同的任务,那么子进程退出的时候,父进程要知道我给他的任务他完成进度完成情况,然后子进程退出的时候,需要父进程等待,然后父进程通过等待的方式,回收子进程资源,获取子进程退出信息。而通过进程等待处理内存泄漏是必须做的,但是对于子进程的任务完成情况父进程不一定会关心,这不是必须的。子进程的退出信息包含在pcb数据结构对象中,wait/waitpid调用操作系统来读取子进程的task_struct内核数据结构对象,用户无法通过操作系统去访问底层,所以父进程也不能直接去拿子进程的内核数据结构对象,只有调用wait/waitpid等系统接口,获取task_struct内核数据结构对象。而若是等待进程失败是什么原因?则表示等待的进程不是它的子进程他才会表现出等待失败的结果所以在等待时父进程只能等待它的子进程。
二、进程等待方法
**进程等待是是什么?**进程等待是通过系统调用wait/waitpid来进行堆进程状态检测与回收的功能
若是没有回收子进程父进程不等待,那么他就会一直处于僵尸状态
等待方法wait和waitpid
wait方法
等待子进程状态发生改变的时候就会回收子进程
等待成功会返回子进程pid,若是失败则会返回-1,子进程退出父进程回收
wait是等待任意一个子进程。
参数status
参数status是进程退出码的信息,它是一个输出型参数,会将wait内部等待的资源带出来也就是退出信息会交给父进程,而这个int 是被当作几部分来使用的,int 4 字节 32个比特位这4字节里面仅仅用到了低16个比特位,最低8位代表子进程是否出异常,低7位代表子进程收到的终止信号,第8比特位代表core dump标志位,而次低8位代表子进程的退出状态,一个整数只用到了低16位,而这低16位又分为两部分,但是总的来说都是为了表示子进程的退出信息描述,当kill -l查看信号时也就解释了维护信号不是从0号开始而是从1号信号开始了,因为最低位都是为1。所以要检测是否收到信号只需要检测低7位比特位是否为1,而次低8位则可以表示进程退出的状态,退出正不正常,若是出错了就会根据次低8位转换对应的退出码然后取得退出码信息。异常计算则是低7位全为1,然后与获得参数按位与status&0x7F
,若是这个status的低7位全为0,那么进程就没有发生异常;退出码计算status先左移8位,表示次低8位计算,进而与次低8位比特位全为1的按位与,若是结果为0则进程退出正常(status>>8)&0xFF
而关于获取退出码和异常检测系统提供了两个宏:进程异常检测 WIFEXITED(status)
,退出码检测WEXITSTATUS(status)
目前来说进程等待是必须的,wait它是等待任意一个进程,那么如果是多个进程呢?他没办法了,因此要用waitpid,waitpid等待进程时可以等待指定进程,那么他该如何等待,等待的又是谁?这是由waitpid的第一个参数决定
waitpid等待为pid为id的进程退出。
pid_t waitpid(pid_t pid, int *status, int options);
waitpid还有第三个参数options,这个参数是代表什么?
当父进程在等待的时候,若是父进程把自己的任务执行完毕了,但是子进程还不退出,而父进程要回收子进程,就会一直等待着子进程退出,而等待子进程的方式就是通过options来设置的,此时在等待的过程中,父进程会陷入一个阻塞状态,系统默认的等待方式为阻塞等待,阻塞等待就是父进程一直在等待,但是在着等待的过程中又不做其他的事情,就是一直等着。然后还有一种等待方式为非阻塞轮询等待!
而options可以设置选项 WNOHANG
,什么意思?这个参数可以设置等待方式为非阻塞等待,就是父进程在等待的过程中可以做自己的事情。就像是拜托一个人做事情,只有他来了才能做,我去找他,去他楼下找他,然后他说还有一会(还没有退出),我就在楼下的树下等着他(阻塞等待),在这个过程中不做任何事情,一直等到他下来为止,等了许久他终于下来了,这就是等待成功!而第二次还需要它的时候,这次结合上次经验,带一本书去等他 并且在等待的过程中一直给他打电话,在等待的过程中他没有下来我就看着书等着他,期间时不时的打电话询问他好了没,这样的等待方式为非阻塞轮询等待,打电话的过程就是为了确定它的状态。非阻塞等待父进程在等待过程中可以做自己的事情,但是这种任务一般都是较为简单的,工作量不大的,因为若是工作量很大的,当父进程在执行任务时子进程刚好退出了那么此时就没有进程来回收子进程,子进程就会造成僵尸。因此父进程就算在等待时执行任务也是那种任务量不大的!等待子进程才是父进程重要的事情,在等待的过程中执行自己的任务是顺带的。父进程创建多个子进程时,在等待的时候将第一个参数设置为-1,然后就可以等待任意一个进程,而还有多少子进程需要等待则用一个引用计数的方式表示还有多少子进程需要等待。在fork创建子进程之后,哪一个进程先运行无法明确,因为这要由调度器根据进程的优先级来管控,但是退出一定是父进程最后退出,因为父进程要回收子进程的退出信息。