当前位置: 首页 > news >正文

Linux中的僵尸进程与wait函数、waitpid函数详解(附图解与代码实现)

目录

僵尸进程的概念及危害

wait函数

waitpid函数

通过status进行僵尸进程校验


僵尸进程的概念及危害

僵尸进程:子进程先于父进程退出,但是系统回收进程资源时,子进程PCB残留,这个进程为僵尸进程

危害:1.PCB残留导致内存泄露

           2.由于PCB创建的数量是固定的,一个僵尸进程会占用一个PCB,从而影响新进程的创建

为什么PCB会有残留呢?

我们假设张三的孩子张思睿出了车祸,医院没救过来,结果医院直接一把火给尸体烧了,你说这合理吗?这显然不合理只有父母有权来决定自己的孩子尸体怎么处理,父母可以通过别的方式来知道自己的孩子是怎么死的,同理,父进程可以通过查看子进程残留的PCB来知道子进程是怎么结束的,这也就是子进程残留PCB的原因

怎么解决僵尸进程这一问题呢?

这里就要用到wait函数和waitpid函数,僵尸进程产生后,只有父进程可以进行回收处理

父进程回收子进程的PCB,可以处理内存泄露,还可以对子进程的退出原因进行校验,通过PCB校验,掌握子进程的退出原因

wait函数

功能:父进程可以调用该函数来清除僵尸进程

pid_t zpid = wait(int* status);//僵尸的英文是zombie,所以这个地方变量名设置为zpid

这是经典的阻塞回收函数,如果有子进程存在,那么就一直阻塞等待子进程死亡,然后回收

头文件  #include<sys/wait.h>

status(输出参数)就是状态,父进程可以通过status来知晓子进程退出的原因,并回收释放PCB

如果传入的是NULL,就只回收释放PCB,不传出子进程退出原因

返回值:

成功就返回僵尸进程的pid(>0),失败就返回-1(没有子进程)

以下是wait函数清除僵尸进程的代码实现

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>//wait函数的头文件int main(void)
{pid_t pid;pid = fork();if (pid > 0){pid_t zpid;printf("parent %d running\n...\n", getpid());if ((zpid = wait(NULL)) > 0)//成功的话wait函数的返回值大于0//回收成功,返回僵尸进程的zpid,NULL-->不返回子进程退出原因{printf("parent wait success zombie pid %d\n", getpid());}while (1){sleep(1);}}else if (pid == 0){printf("Child %d Running\n...\n", getpid());sleep(10);exit(0);//这个地方,子进程退出,PCB残留,产生僵尸进程,进入判断if ((zpid = wait(NULL)) > 0)}else{printf("fork call failed\n");exit(0);}return 0;
}

waitpid函数

pid_t zpid = waitpid(pid_t pid , int* status , int opt);

支持非阻塞回收,如果当前子进程无法回收则返回

头文件:#include<sys/wait.h>

Pram:

pid回收方式
-1回收任意子进程
>0

指定一个子进程的pid,然后回收该子进程

0

 可以回收与调用进程(父进程)同组的所有子进程(同组回收)

< -1

 可以回收与调用进程(父进程)同组的所有子进程(同组回收)

Status    校验子进程的退出原因,传入NULL则不校验

Opt  设置waitpid的工作模式,传入参数WNOHANG,则将waitpid改为非阻塞工作模式

返回值:

回收成功返回僵尸进程的zpid

回收失败返回 -1(表示没有子进程)

非阻塞返回0(表示当前子进程不可回收,立即返回)

以下是waitpid函数清除僵尸进程的代码实现

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>int main(void)
{pid_t pid;pid = fork();if (pid > 0){pid_t zpid;while ((zpid = waitpid(-1, NULL, WNOHANG)) != -1)//因为我们传入了WNOHANG,waitpid函数现在为非阻塞模式//那么就有两种情况,返回值>0 和 ==0 两种情况{if (zpid > 0){printf("parent wait success , zpid = %d\n", zpid);}else if (zpid == 0){printf("Parent Running...\n");sleep(1);}}}else if (pid == 0)//到了子进程,子进程进入该判断{sleep(10);exit(0);}return 0;
}

wait函数和waitpid函数的区别

相比于阻塞回收,非阻塞回收更灵活,可以释放父进程让其执行其他的任务

通过status进行僵尸进程校验

前面只是说了父进程怎么回收僵尸进程,而没有考虑查询子进程退出变成僵尸进程的原因

那么接下来我们说一下通过status进行僵尸进程的校验的过程,先看下下面这张图

 校验过程:
1.父进程调用wait/waitpid函数,其中的参数status得到了子进程的退出原因

2.进入两个判断,分别是子进程正常退出和子进程异常退出的两个判断

注意,这两个判断不是if--else的关系,而是要用两个if判断

3.如果子进程为正常退出,比如像return 0;   exit(0);    exit(8)这样退出即为正常退出,那么WIFEXITED(status)的返回值为true,可以通过调用WEXITSTATUS(status)来获取子进程的退出码

4.如果子进程为异常退出,比如像因为硬件访问错误这样退出即为异常退出,那么WIFSIGNALED(status)的返回值为true,可以通过调用WTERMSIG(status)获取杀死子进程的信号编号

以下是通过status进行僵尸进程校验的过程的代码实现

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>int main(void)
{pid_t pid;int i;for (i = 0; i < 2; i++)//循环创建了两个子进程{pid = fork();if (pid == 0){break;}}if (pid > 0){int status;printf("Parent pid %d\n Wait..\n", getpid());pid_t zpid;while ((zpid = wait(&status)) > 0)//子进程退出校验{if (WIFEXITED(status)){printf("Parent Wait Success , Zombie pid %d exit error Print ExitCode %d\n", zpid, WEXITSTATUS(status));}if (WIFSIGNALED(status)){printf("Parent Wait Success , Zombie pid %d exit error Signal No %d\n", zpid, WTERMSIG(status));}}}else if (pid == 0){if (i == 0){printf("First child pid %d Exit...\n", getpid());exit(7);}else if (i == 1){while (1){printf("Child pid %d while(1) sleep..\n", getpid());sleep(1);}}}else{perror("fork call failure\n");exit(0);}return 0;
}

今天的学习记录到此结束啦,咱们下篇文章见,ByeBye!

http://www.xdnf.cn/news/829549.html

相关文章:

  • 空间数据分析和空间统计工具库PySAL入门
  • 分布式系统中的“无状态”和“有状态”详解
  • 端口聚合、端口镜像及ACL实验
  • 实用网站大全
  • ScaleType的各种类型的白话解释
  • Activex、OLE、COM、OCX、DLL之间区别、联系
  • MATLAB 的gui详细设计
  • 什么是RoR
  • 程序员的自我修养
  • C语言中的数据结构及编程实例
  • 【sylar】框架篇-Chapter9-hook 模块
  • 【转】ubuntu设置快捷键关闭触摸板
  • 常用的webservice服务接口
  • [Cisco Packet Tracer下载教程安装教程]Cisco Packet Tracer怎么设置成中文?3560-24PS为什么ip helper-address 192.168.8.3报错
  • 数据分析必备:12个“地表超强”数据可视化工具推荐!
  • Java基础入门教程
  • MFC中MultiByteToWideChar和WideCharToMultiByte
  • 图文讲解flashfxp教程 flashfxp详细教程
  • Windows计划任务
  • Petri网的介绍
  • LeapMotion 简介
  • vi / gvim编辑器的基本使用
  • USRP简介
  • 启动应用程序出现ws2_32.dll找不到问题解决
  • 微PE安装使用教程(非常详细)从零基础入门到精通,看完这一篇就够了
  • Flutter中AspectRatio、Card 卡片组件
  • 【设计模式】叩心自问:什么是设计模式? 设计模式的目的是什么?设计模式依据哪些(七种)原则设计的?设计模式有哪些?分类?
  • Linux下安装QQ
  • 网络安全常见十大漏洞总结(原理、危害、防御)_网络安全常见漏洞类型_漏洞基本原理
  • 基础SQL语法语句大全(一篇学会所有SQL语句)