进程等待与wait&waitpid

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ArchyLi/article/details/78734887

一、进程等待的简介

(1)进程等待用来干什么的

我们通过之前学习过的知识知道了,如果一个进程如果在终止的时候会关闭它所有的文件描述符,同时释放在用户空间分配的内存,但是还保存着PCB等相关信息,与此同时还保存了一些其他的的相关信息。

如果此时进程正常终止,则其中保存着它的退出状态;如果是异常退出,则这些其他的相关信息会保存着该进程的终止信号是哪个。

这个时候我们的子进程的父进程可以调用wait和waitpid获取这些信息,然后根据这些信息来选择解决这个进程。

正常或异常终止发送信号

当一个进程正常或异常终止时,内核就向其父进程发送一个SIGCHLD信号。因为子进程终止是一个异步事件,所以发生这种信号也是内核向父进程发的异步通知。

父进程可以选择忽略该信号,或者提供一个该信号发生时即被调⽤用执⾏行的函数。对于这种信号的系统默认动作是忽略它。

查看进程退出状态

我们如果要查看一个进程的退出状态,则可以在Shell中使用‘$?’来查看进程的退出状态,因为shell是它的父进程,当它终止时shell调用wait或者waitpid得到这个子进程的退出状态,同时清除这个进程。

(2)为什么要有进程等待

我们通过进程等待来获取进程退出的时候的相关信息,来对进程进行一些处理。

(3)进程等待的必要性

  • 子进程退出如果父进程不管子进程的任何资源,就可能产生“僵尸进程”,从而导致内存泄漏。
  • 一个进程如果变成僵尸进程,那么即便我们用kill也没有没有办法杀掉它。(因为我们当然没有办法杀死一个已经死掉了的进程)
  • 我们需要知道父进程分配给子进程的任务它完成的怎么样,是正常运行完成,还是运行出错,又或者是异常退出。

所以综上几点表明,父进程通过进程等待的方式,回收子进程的资源,同时来获取子进程退出的信息。

(4)调用wait与waitpid的进程可能会发生什么情况

  1. 如果其所有的进程都还在运行,则阻塞。
  2. 如果一个子进程已经终止,正在等待父进程获取其终止状态,则取得该子进程的终止状态立刻返回。
  3. 如果它没有任何子进程,则立即出错返回。

二、进程等待的方法

进程等待的方式主要有两个方法,一个是wait与waitpid。

wait与waitpid的区别

wait会令调用者阻塞直至某个子进程终止;

waitpid提供了wait函数不能实现的3个功能:

  1. waitpid等待参数指定的子进程, 而wait则返回任一终止状态的子进程;
  2. waitpid提供了一个wait的非阻塞版本;
  3. waitpid支持作业控制(以WUNTRACED选项). 用于检查wait和waitpid两个函数返回终止状态的宏: 这两个函数返回的子进程状态都保存在status指针中, 用以下3个宏可以检查该状态:

WIFEXITED(status):
若为正常终止, 则为真. 此时可执行 WEXITSTATUS(status): 取子进程传送给exit或_exit参数的低8位.
WIFSIGNALED(status):
若为异常终止, 则为真.此时可执行 WTERMSIG(status): 取使子进程终止的信号编号.
WIFSTOPPED(status):
若为当前暂停子进程, 则为真. 此时可执行 WSTOPSIG(status): 取使子进程暂停的信号编号

三、wait

我们首先来看下wait方法在Linux下的说明

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
  • 返回值
    我们可以看到,它的返回值类型是一个pid_t的类型。
    它成功返回被等待进程的pid,失败则返回-1。
  • 参数
    输出型参数,获取子进程退出状态,不关心则可以设置成NULL。

进程由于收到了SIGCHLD而调用了wait,期望wait立刻返回,但是任意时刻调用wait,则进程可能会被阻塞。

四、waitpid

#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);
  • 返回值:
    • 当正常返回的时候waitpid返回收集到的子进程的进程ID;
    • 如果设置了选项WNOHANG,而调用中waitpid发现已经没有可以退出的子进程可以收集,则返回0;
    • 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
    • 当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD.
  • 参数:
    • pid:
      • pid=-1,等待任意一个子进程,与wait等效;
      • pid>0, 等待其进程ID与pid相等的子进程。
      • pid=0,等待其进程组ID等于调用进程组ID的任一个子进程。
      • pid<-1,等待其进程组ID等于pid绝对值的任一个子进程。
    • status:
      • WIFEXITEN(status):若为正常终止子进程返回的状态,则为真。(一般用来查看进程是否正常退出)
      • WEXITSTATUS(status): 若WEXITSTATUS非零,提取子进程退出码。(一般用来查看进程的退出码)
    • options:
      • WNOHANG:若pid为指定的子进程没有结束,则waitpid()函数返回0,不等待。若正常退出,则返回该子进程的ID。

五、关于status参数

我们知道在wait与waitpid中都有status参数,他并不简简单单的是一个整型变量,因为父进程和子进程之间所有的状态交互都要通过这个参数来表示,因此这个int类型的status的若干bit位都有特殊含义的,所以它的编码比较重要。

所以status指出了子进程是正常退出还是异常退出的,以及正常结束时的返回值,或者是被哪一个信号结束或者进程的退出码是多少等信息,这些信息都被保存在这个参数的不同的二进制中,开发者通过设计一个专门的宏来完成了这个工作。

猜你喜欢

转载自blog.csdn.net/ArchyLi/article/details/78734887
今日推荐