【Linux】进程等待

什么是进程等待?

通过系统用wait/waitpid,来进行对子进程进行状态检测与回收的功能!


为什么要有进程等待?

  1. '僵尸进程'无法被杀死,只能通过进程等待来回收, 进而解决内存泄漏问题。
  2. 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息----- 子进程运行完成,结果对还是不对, 或者是否正常退出。(父进程可以关心也可以不关心,这条不是必选)

补充(关于父子进程的理解):

其实我们到目前为止,不管是在命令行上所启动的进程 ,还是我们自己在代码层面 上创建出来的进程,它都叫做子进程

Linux整个的进程结构本质就是一些父子关系的多叉树 结构。那么我们命令行启动的所有的进程或者任务,最终其实都是父进程bash的子进程 。想象一下,如果我们自己在fork的时候,虽然出现了父进程,但这个父进程它也是别人的子进程


系统怎么使用进程等待的?

代码验证:

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

int main()
{
  pid id=fork();
  if(id<0)
  {
    perror("fork");
    return 1;
  }

  else if(id==0)
  {
    int cnt=5;
    while(cnt--)
    {
        printf("I am child pid:%d,ppid:%d,cnt:%d \n",getpid(),getppid(),cnt);
        sleep(1);
    }
    exit(0);
  }
  else
  {
    //parent
    int cnt=10;
    while(cnt--)
    {
        printf("I am child pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);
        sleep(1);
    }
    pid_t ret=wait(NULL);
    if(ret==id)
    {
        printf("wait success ,ret:%d\n")
    }
    sleep(5);
  }
  return 0;

}

关于wait接口:

fork给我们对应的父子进程都会返回id值,子进程返回pid值等于0,

父进程的返回的pid其实这个就是子进程的pid。

wait:它就是用来让当前对应的父进程来进行等待子进程。

那么我们等待成功的时候ret是等待的子进程的pid。

换句话说,为什么要给父进程返回子进程的PID呢?

就是要用来判断我们当前父进程等待的时候等待的是哪个子进程,ret这个值返回值小于0小于0说明等待失败。

代码运行逻辑:

就是很显然这个程序一旦跑起来了:

那么对应的进程呢先创建父子进程
在前5秒的时候,父子都在运行,

5秒之后 ,子进程先退了之后变成僵尸状态等待回收

,但是我们的父进程依旧没有进行wait,因为它还在执行前面的while。

再过5秒之后 ,我们父进程回收子进程僵尸状态,最后父进程也结束;

所以进程等待是很有必要的!!!

如果我们有多个子进程需要回收,就需要创建多个wait来对其进行回收

如果子进程不退出,父进程默认在wait的时候,调用这个系统调用的时候,也就不返回,默认叫做阻塞状态!

关于waitpid接口:

pid_ t waitpid(pid_t pid, int *status, int options);

返回值:

当正常返回的时候waitpid返回收集到的子进程的进程ID;

如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;

如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

参数:

pid:

Pid=-1,等待任一个子进程。与wait等效。

Pid>0.等待其进程ID与pid相等的子进程。

status:

WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)

WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

options:

WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进 程的ID。

这里的waitpid参数这么写和wait的达到的效果是差不多的

关于status参数:

它是一个int*,也就是一个指针。但实际上呢,我们给它传参的时候确实是要传一个指针的。

只不过这里是为了通过wait或waitpid拿到指定进程或者任意一个进程它所对应的退出结果的。

第一个从语法角度,这个整数,它是一个输出型参数。

关于输出型参数:

关于输出型参数是c,c++语法的基础,就是期望通过对应的指针把函数内部所对应的数据带出来。

因为大家都知道我们传参一般都是要给函数传参的。

但有些形参最后我们可以把实际化之后变成指针。

然后通过status把函数内部的资源带出去,比如说对空间,比如说我们对应的返回值。

所以这种把值带出来的这种参数类型 ,我们叫做输出型参数
我的传参不是为了交给你对应的,这个函数什么,而是想让你函数交给我什么,这叫做输出型参数来。

第二,int看起来是整数,但是它这个int是被当做几部分使用的不要把这个int当做一个整数来看。

因为一个int在我们现有的这个平台当中

一个int类型占32比特位,那么也就意味着:我们其实是可以把我们所对应的这个int类型呢,可以看作成比如8个了、或者16个了。

所以把它分批可以表达不同的含义。

所以呢,这个int它是被当做几部分来使用 的。

所以对我们来讲,我们想获取对应的结果呢。

在这里int就得定一个status变量这个变量名字可以随便起,只要它是个整数就行了。

一旦这个子定程它退出了。

我们会把它的退出信息拷贝到这个status指针所指向的变量当中。

所以当我们等待成功的时候,我们此时就能够得到这个子进程的对应退出信息。

其中这个status,它高16位不考虑,我们只考虑它的低16位

严格意义上讲是第8位,就是它的最低的。
那8个比特位用来表示的是我们这个当前进程是否出异常的问题

我们一个进程在异常终止时,一个子进程或者一个进程的异常时,本质是该进程收到信号了。

所以我们只要判断终止信号,这里的低7个比特位是否为0就能证明你的代码是否跑完

可是跑完就对吗?

不一定。

我们可以通过这里对应的次第8位: 退出状态来得知子进程退出结果,所以就叫做退出状态。

所以退出状态为0,表示代码跑完结果正确,那么信号为0。

退出状态为1,代码跑完结果不正确,不正确的原因每一个不同的数字可以表示出错的不同原因。

父进程要拿子进程的状态数据或者任意数据,为什么必须要wait等系统调用呢?

首先父子进程之间是具有独立性的

所以你只能通过我们官方渠道----waitpid来指定进程获取它的特殊结果,并且父进程只能wait它对应的子进程。

相关推荐
我们的五年5 分钟前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
爱吃青椒不爱吃西红柿‍️25 分钟前
华为ASP与CSP是什么?
服务器·前端·数据库
IT果果日记27 分钟前
ubuntu 安装 conda
linux·ubuntu·conda
Python私教29 分钟前
ubuntu搭建k8s环境详细教程
linux·ubuntu·kubernetes
羑悻的小杀马特42 分钟前
环境变量简介
linux
小陈phd1 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
运维&陈同学1 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
是阿建吖!1 小时前
【Linux】进程状态
linux·运维
hzyyyyyyyu2 小时前
内网安全隧道搭建-ngrok-frp-nps-sapp
服务器·网络·安全
明明跟你说过2 小时前
Linux中的【tcpdump】:深入介绍与实战使用
linux·运维·测试工具·tcpdump