进程之 回收子进程之避免僵尸进程的产生

简介: wait() 与 waitpid() 函数的使用.

wait() 与 waitpid() 函数的使用.

  因为前段时间博主没有把Windows系统带走所以不能实时更新博客,请见谅。接下来就让我们继续开始进程的世界吧。


前面我们说到了如何创建多个子进程那么现在就让我们来消灭那些僵尸进程吧。

那么我们回顾一下,僵尸进程是不能使用kill命令清除掉的。因为kill命令只是用来终止进程的,而僵尸进程本身已经终止了。那么我们有什么办法来清楚僵尸进程呢?

        如何查看僵尸进程:

20191027193841733.png


销毁僵尸进程1. wait函数

父进程调用wait 函数可以回收子进程终止信息。我们的wait函数由三个功能:

1. 阻塞等待子进程退出

2. 回收子进程残留资源

3. 获取子进程结束的状态。

(博主在这里解释一下什么是子进程结束状态。因为在程序运行时,子进程可能是正常结束,但也可能异常结束,可能是调用kill命令直接终止,那么,如果子进程不能保留自己的进程结束状态,那么父进程就不知道紫禁城是如何结束的)。

#include<sys/wait.h>
pid_t wait(int *status);
  --->成功: 返回终止的子进程ID
      失败: 返回-1


下面给出电子书中的内容,大家可以记一下下面的结构.()其实不是很完整,博主将在下面给出大家更好的体系,大家可以跟博主一样使用下面的语句)。

2019102719402682.png

上面可以看出图片上如果是正常返回那么我们就能知道正常终止的子进程ID是多少,但是大家有没有想过,万一是异常终止呢???那我么应该怎么去知道是哪一个终止了我们的子进程呢??所以这就引出了我们下面的内容。

为大家补充两个宏(前面两个和书上的是一致的,后面两个宏为补充的)


1.WIFEXITED(status) 为非0 -->进程正常结束

WEXITSTATUS(status) 如上宏为真,使用此宏 --> 获取进程退出状态 (exit的参数)也就是返回你的exit(x) 返回x的数值。


2.WIFSIGNALED(status) 为非0 -->进程异常终止

WTERMSIG(status) 如上宏为真,使用此宏 --> 取得使进程终止的那个信号的编号。就比如说你使用 kill -9 5031(假设5031是子进程ID)那么返回的就是 9 也就是你用9号来终止的子进程。


也就是说在我们使用wait函数之后,我们可以使用下面的代码来检测子进程是否正常终止。

if(WIFEXITED(status)){
  puts("Normal termination!");
  printf("child pass num :%d,"WEXITSTATUS(status));
}else{
  if(WIFSIGNALED(status) ){
    puts("error termination!");
    printf("child killed num :%d,"WTERMSIG(status));
  }
}
根据上面的内容编写不仅涵盖了正常情况而且未知情况我们也可以预见,因此更加符合
  防御式编程,希望大家能够就记住。


看上上面的介绍大家是不是觉得wait 函数已经很好了,正常情况我们能够知道,就连错误情况我们也能了解到,那为什么还需要waitpid函数呢??


其实是非常有必要的,博主下面给出一个例子,大家就能知道 waitpid函数的重要性了。


因为wait 函数具有阻塞性,当我们调用 wait函数是,如果没有已经终止的子进程,那么我们的程序就阻塞了啊!!!必须等到由子进程终止程序才会继续运行,在编程领域这可是非常不好的事情。所以接下来我们就隆重有请我们的waitpid函数的登场。


销毁僵尸进程2

wait函数会引起程序阻塞,那么我们就可以考虑条用 waitpid函数。这就是我们防止僵尸进程的第二种方法,也是防止阻塞的方法。


#include<sys/wait.h>
pid_t witpid(pid_t pid, int *status, int options);
参数:
  第一个参数 pid_t pid: 
      > 0 回收指定ID的子进程  
      -1 回收任意子进程(相当于wait)
      0 回收和当前调用waitpid一个组的所有子进程
      < -1 回收指定进程组内的任意子进程
  第二个参数 int *status. 和wait一样的   
  第三个参数 int options 传递头文件sys/wait.h 中声明的常量 WNOHANG,表示解释没有终止的子进程也不会进入阻塞状态,而是返回 0 并退出函数。
返回值:
  成功:返回终止的子进程ID(或0)
  失败:返回-1
waitpid同样可以使用我们的上面介绍的if else模型进行判断。
下面也给出大家waitpid的使用模型吧(以后一般都是使用waitpid函数来回收子进程!)
  下面给出电子书上的代码(改进版)。
#include<stdio.h>
#include<uistd.h>
#include<sys/wait.h>
int main(int argc, char *argv[]) {
  int status;
  pid_t pid = fork(); //创建子进程
  if (pid == -1) {
    printf("fork() error");
    exit(-1);
  }else if (pid == 0) { //子进程休眠后结束,目的是为了检测我们的 waitpid是否阻塞的小测试
    sleep(15);
    exit(24);   
  } else {  //这就是父进程了
    while (!waitpid(-1, &status, WNOHANG)) {
      sleep(3);
      puts("sleep 3sec");
    }
    if (WIFEXITED(status)) {
      puts("Normal termination!");
      printf("child pass num :%d,"WEXITSTATUS(status)); //如果正常的话我们能看到24
    } else {
      if (WIFSIGNALED(status)) {
        puts("error termination!");
        printf("child killed num :%d, "WTERMSIG(status));
      }
      return 0;
    }
  }
}

注意:“注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。 ”

好啦这就是waitpid 和 wait函数啦,他们最大的区别就是waitpid能设置为非阻塞(也能设置为阻塞),wait只能阻塞等待。


谢谢大家的观看。


目录
相关文章
|
2月前
|
Linux C++
Linux c/c++进程之僵尸进程和守护进程
这篇文章介绍了Linux系统中僵尸进程和守护进程的概念、产生原因、解决方法以及如何创建守护进程。
33 0
|
3月前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
4月前
|
C语言
【C语言】多进程创建和回收
【C语言】多进程创建和回收
83 0
|
5月前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
131 2
|
6月前
|
JavaScript 前端开发 Shell
深入Node.js的进程与子进程:从文档到实践
深入Node.js的进程与子进程:从文档到实践
|
7月前
|
安全 Java
多线程(CAS, ABA问题, Runnable & Callable & 僵尸线程 & 孤儿进程)
多线程(CAS, ABA问题, Runnable & Callable & 僵尸线程 & 孤儿进程)
69 1
让“父进程”可以有自己的工作,不需要因为为了“子进程”回收资源而堵塞。但也要满足“子进程”退出后的资源能被立马回收。(不能使用任何的进程通信机制 比如:信号等)
让“父进程”可以有自己的工作,不需要因为为了“子进程”回收资源而堵塞。但也要满足“子进程”退出后的资源能被立马回收。(不能使用任何的进程通信机制 比如:信号等)
|
7月前
|
存储 Linux
【linux进程控制(二)】进程等待--父进程是如何等待子进程死亡的?
【linux进程控制(二)】进程等待--父进程是如何等待子进程死亡的?
|
7月前
|
Linux Shell 调度
【linux进程(四)】僵尸进程和孤儿进程概念&进程优先级讲解
【linux进程(四)】僵尸进程和孤儿进程概念&进程优先级讲解