什么是进程等待?

什么是进程等待

在了解进程等待之前,我们要回顾一下什么是僵尸进程:是指一个已经终止执行的进程,但其父进程还没有通过 wait() 系统调用来获取该进程的退出状态信息。当一个进程正常退出或者被终止时,其所占用的系统资源会被操作系统及时回收释放,而其退出状态(退出码)会被传递给其父进程。然而,如果父进程没有合理处理该状态,那么子进程将会变成一个僵尸进程。僵尸进程会占据系统资源,也就是僵尸进程的退出信息等资源,如果不即使清理僵尸进程的话可能会导致进程表被占满,从而导致系统运行缓慢甚至不稳定。

避免僵尸进程的产生:父进程通过调用 wait() 或 waitpid() 系统调用来处理已经终止的子进程,也就是处理僵尸进程所占据的资源信息。

为什么要进行进程等待

  • 解决子进程僵尸问题带来的内存泄漏
  • 我们知道父进程会通过等待子进程,从而接收子进程的退出信息(进程退出码信号编号)而进程退出码标识的就是该进程运行完的退出结果,而信号编号标识的是该进程是什么导致的异常退出。  

怎样等待

 wait方法

wait() 是一个系统调用函数,用于父进程等待子进程的状态改变。它可以用来处理僵尸进程。wait() 函数的作用是:阻塞父进程的执行,直到一个子进程发生状态变化。当子进程终止时,内核会将该进程的退出状态保存在 status 中,并返回该子进程的进程ID(PID)。

pid_t wait(int*status);

返回值:成功则返回被等待进程pid,失败返回-1。

参数:输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
void do_work()
{
    int count=3;
    while(count)
    {
        printf("我是子进程,mypid=%d myppid=%d count=%d\n",getpid(),getppid(),count--);
        sleep(1);
    }
}
int main()
{
    pid_t i=fork();
    if(i==0)//子进程
    {
        do_work();
    }
    else//父进程
    {
        cout<<"等待之前"<<endl;
        pid_t ret=wait(NULL);
        cout<<"等待之后"<<endl;

        if(ret==i)//fork之后父进程会返回子进程的id
        {
            cout<<"等待成功"<<endl;
        }
    }

    return 0;
}

 我们知道fork之后会创建子进程,而且fork后面的代码子进程和父进程都会执行,而父子进程的执行先后顺序取决于调度器的调度,但是我们要知道父进程要接收子进程退出时的资源信息,所以可以明确:进程正常退出时,父进程一定后于子进程退出。而且父进程调用wait的时候会等待子进程执行完。

注意: wait() 函数只能处理直接子进程的状态变化,无法处理所有子进程的退出状态。如果希望处理所有子进程的状态变化,可以使用循环结构来多次调用 wait() 或者使用信号处理机制来实现。

 waitpid方法

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

waitpid() 函数等待成功会返回值为子进程的进程ID

第一个参数 pid 指定需要等待的子进程的进程ID。Pid=-1,等待任意一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。

代替wait使用 

void do_work()
{
    int count=3;
    while(count)
    {
        printf("我是子进程,mypid=%d myppid=%d count=%d\n",getpid(),getppid(),count--);
        sleep(1);
    }
}
int main()
{
    pid_t i=fork();
    if(i==0)//子进程
    {
        do_work();
    }
    else//父进程
    {
        cout<<"等待之前"<<endl;
        pid_t ret=waitpid(-1,NULL,0);//三个参数(等价于wait)
        cout<<"等待之后"<<endl;
        if(ret==i)//父进程会返回子进程的id
        {
            cout<<"等待成功"<<endl;
        }
    }

    return 0;
}

 

第二个参数的使用

参数 status 是一个指向整型变量的指针,用于保存子进程的退出状态信息。
如果不关心子进程的退出状态,可以将 status 设置为 NULL。

wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。操作系统会根据该参数,将子进程的退出信息反馈给父进程status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):

 我们知道子进程正常退出时会有退出码返回给父进程,而退出码标识该子进程任务的执行情况是否完成。但是子进程不仅仅有正常终止,还有可能会异常终止(收到操作系统发来的信号),所以我们还要接收子进程退出时的信号。所以当我们父进程在等待子进程时会得到两个数字(1.退出码 2.信号码)

 退出码接收

int main()
{
    pid_t i=fork();
    if(i==0)//子进程
    {
        do_work();
        exit(10);
    }
    else//父进程
    {
        cout<<"等待之前"<<endl;
        int sta=0;
        pid_t ret=waitpid(-1,&sta,0);
        cout<<"等待之后"<<endl;
        
        if(ret==i)//父进程会返回子进程的id
        {
            printf("子进程正常退出,pid:%d ,ret:%d ,exit code:%d ,exit sigal:%d \n",getpid(),ret,(sta>>8)&0xFF,sta&0x7F);//这里的&操作符就是得到对应的比特位
        }
    }

    return 0;
}

 退出信号接收

 以上就是所有退出信号而8号对应的就是SIGFPE

第三个参数的认识

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

第三个参数我们一般默认是设为0的,而设为0所代表的含义是阻塞等待,就是父进程会一直等待子进程运行,直到子进程结束之后才开始调用wait函数,从而接收子进程的退出码和信号。但是显然阻塞等待缺陷是:父进程什么操作都干不了,必须等待子进程退出才可以继续执行父进程后续的操作。

而第三个参数为WNOHANG时则意味着非 阻塞等待,也就是说会进行重复的多次调用waitpid函数接口(尽管子进程未退出)。若子进程未退出则waitpid函数返回0,表明还需要继续等待;而返回值大于0则表明返回的是所等待的子进程ID,等待成功且子进程结束;还有返回值小于0的时候则表明等待失败。所以我们非阻塞等待一般会采用循环执行。也称为非阻塞轮询方案。而非阻塞等待相较于阻塞等待的优势就是还可以在进行等待的过程中,父进程可以顺便做一些占据时间不多的事情,而不是像阻塞等待一样一直等待着。

void do_work()
{
    int count=3;
    while(count)
    {
        printf("我是子进程,mypid=%d myppid=%d count=%d\n",getpid(),getppid(),count--);
        sleep(1);
    }
}

int main()//非阻塞等待
{
    pid_t i=fork();//为父进程返回子进程的id,为子进程返回0
    if(i==0)
    {
         //子进程
         do_work();
         exit(0);
    }
    while(1)//轮询等待
    {

        //父进程
        pid_t ret = waitpid(i,NULL,WNOHANG);//等待成功返回所等待进程的id
        if(ret==0)
        {
            cout<<"等待中"<<endl;
        }
        else if(ret==i)
        {
            cout<<"等待成功,所等待进程的id:"<<ret<<endl;
            break;
        }
        else
        {
            cout<<"等待失败"<<endl;
            break;
        }
        sleep(1);
    }

    return 0;
}

 


 多进程的等待

void do_work()
{
    int count=3;
    while(count)
    {
        printf("我是子进程,mypid=%d myppid=%d count=%d\n",getpid(),getppid(),count--);
        sleep(1);
    }
}

int main()
{
    int i=0;
    for(i=0;i<10;i++)
    {
        pid_t id=fork();
        if(id==0)//子进程进入
        {
            do_work();
            exit(1);
        }
    }

    for(i=0;i<10;i++)
    {
        pid_t ret = waitpid(-1,NULL,0);//等待任意一个子进程等价于wait
        if(ret>0)
            printf("进程等待成功,pid:%d\n",ret);
    }

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/130172.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

rust实现quic服务端和客户端

演示如何使用 Quinn 库实现一个简单的 QUIC 客户端和服务器。QUIC 是一种基于 UDP 的协议&#xff0c;用于在互联网上进行快速和安全的通信。 在程序中&#xff0c;使用了 Rust 的标准库中的 error、net 和 sync 模块&#xff0c;以及第三方库 tokio 和 quinn。程序使用了 asy…

C# OpenCvSharp DNN HybridNets 同时处理车辆检测、可驾驶区域分割、车道线分割

效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Numerics; using System.Text; using System.Windows.Forms;namespace OpenCvSharp_D…

如何使用CORS和CSP保护前端应用程序安全

前端应用在提供无缝用户体验方面起着核心作用。在当今互联网的环境中&#xff0c;第三方集成和API的普及使得确保强大的安全性至关重要。安全漏洞可能导致数据盗窃、未经授权访问以及品牌声誉受损。本文将向您展示如何使用CORS和CSP为您的网页增加安全性。 嗨&#xff0c;大家好…

使用Redis实现热搜功能

Redis热搜 原理数据类型redis操作简单实现 实操封装方法执行方法最后使用springboot的定时任务对热搜榜单进行维护 原理 使用redis实现热搜的原理就是维护一个zset集合&#xff0c;然后使用score作为当前搜索词的搜索量&#xff0c;score越高的搜索词就说明该搜索词热度越高。…

【蓝桥杯选拔赛真题17】C++时间换算 第十二届蓝桥杯青少年创意编程大赛C++编程选拔赛真题解析

目录 C/C++时间换算 一、题目要求 1、编程实现 2、输入输出 二、算法分析 <

USB偏好设置-Android13

USB偏好设置 1、USB偏好设置界面和入口2、USB功能设置2.1 USB功能对应模式2.2 点击设置2.3 广播监听刷新 3、日志开关3.1 Evet日志3.2 代码中日志开关3.3 关键日志 4、异常 1、USB偏好设置界面和入口 设置》已连接的设备》USB packages/apps/Settings/src/com/android/setting…

CSS 移动端 1px(线条/边框) 不同机型上显示粗细不同,解决办法

由于不同的手机有不同的像素密度导致的。如果移动显示屏的分辨率始终是普通屏幕的2倍&#xff0c;1px的边框在devicePixelRatio2的移动显示屏下会显示成2px&#xff0c;所以在高清瓶下看着1px总是感觉变胖了 <!DOCTYPE html> <html lang"en"> <head&g…

快速修复因相机断电导致视频文件打不开的问题

3-5 本文主要解决因相机突然断电导致拍摄的视频文件打不开的问题。 在日常工作中&#xff0c;有时候需要使用相机拍摄视频&#xff0c;比如现在有不少短视频拍摄的需求&#xff0c;如果因电池突然断电的原因&#xff0c;导致拍出来的视频播放不了&#xff0c;这时候就容易出大…

自适应模糊PID控制器在热交换器温度控制中的应用

热交换器是一种常见的热能传递设备&#xff0c;广泛应用于各个工业领域。对热交换器温度进行有效控制具有重要意义&#xff0c;可以提高能源利用效率和产品质量。然而&#xff0c;受到热传导特性和外部环境变化等因素的影响&#xff0c;热交换器温度控制难度较大。本文提出一种…

个人怎么投资伦敦金?

伦敦金是一种被广泛交易的黄金合约&#xff0c;是投资者参与黄金市场的一种交易方式。伦敦金投资也是黄金交易中最为方便快捷的一个种类&#xff0c;在黄金交易市场中占有较大的比例&#xff0c;每天都有来自全球各地的投资者参与买卖&#xff0c;是实现财富增益的一个有效途径…

数据库数据恢复—MSSQL报错“附加数据库错误823”如何恢复数据?

数据库故障&分析&#xff1a; MSSQL Server数据库比较常见的报错是“附加数据库错误823”。如果数据库有备份&#xff0c;只需要还原备份即可&#xff1b;如果无备份或者备份不可用&#xff0c;则需要使用专业的数据恢复手段去恢复数据。 MSSQL Server数据库出现“823”的报…

宠物医院信息展示预约小程序的效果如何

养宠家庭越来越多&#xff0c;随之带来的就是宠物健康问题&#xff0c;生活条件稍微好点的家庭&#xff0c;只要宠物生病或洗护、寄养、美容等就会前往宠物医院&#xff0c;而近些年来&#xff0c;市场中的宠物医院也在连年增加&#xff0c;可以预见市场需求度较高。 而对宠物…

基于遗传算法优化的直流电机PID控制器设计

PID控制器是工业控制中常用的一种控制算法&#xff0c;通过不断调节比例、积分和微分部分来实现对系统的稳定控制。然而&#xff0c;在一些复杂系统中&#xff0c;传统的PID参数调节方法可能存在局限性。本文将介绍一种基于遗传算法优化的直流电机PID控制器设计方法&#xff0c…

[极客大挑战 2019]BuyFlag 1(两种解法)

题目环境&#xff1a; FLAG NEED YOUR 100000000 MONEY flag需要你的100000000元 F12瞅瞅源代码&#xff1a; if (isset($_POST[password])){ $password $_POST[password]; if (is_numeric($password)) { echo "password cant be number" } elseif ($pas…

Android RxJava3 原理浅析

使用 val retrofit Retrofit.Builder().baseUrl("https://api.github.com/").addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava3CallAdapterFactory.create()).build()val api retrofit.create(API::class.java)api.getRepo("…

数据结构之单链表

大家好&#xff0c;我们今天来简单的认识下单链表。 链表的概念及结构 概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。 单链表就像图中的火车一样&#xff0c;是由一节一节车厢链接起来…

第12章 PyTorch图像分割代码框架-3:推理与部署

推理模块 模型训练完成后&#xff0c;需要单独再写一个推理模块来供用户测试或者使用&#xff0c;该模块可以命名为test.py或者inference.py&#xff0c;导入训练好的模型文件和待测试的图像&#xff0c;输出该图像的分割结果。inference.py主体部分如代码11-7所示。 代码11-7 …

Linux imu6ull驱动- led

一、GPIO模块结构 开始来啃手册了&#xff0c;打开我们的imx6ull手册。本章我们编写的是GPIO的&#xff0c;打开手册的第28章&#xff0c;这一章就有关于IMX6ULL 的 GPIO 模块结构。 mx6ull一共有5 组 GPIO&#xff08;GPIO1&#xff5e;GPIO5&#xff09; GPIO1 有 32 个引脚&…

C/C++输出硬币翻转 2021年6月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C硬币翻转 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C硬币翻转 2021年6月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 假设有N个硬币(N为不大于5000的正整数)&#xff0c;从1…

C语言--汉诺塔【内容超级详细】

今天与大家分享一下如何用C语言解决汉诺塔问题。 目录 一.前言 二.找规律⭐ 三.总结⭐⭐⭐ 四.代码实现⭐⭐ 一.前言 有一部很好看的电影《猩球崛起》⭐&#xff0c;说呀&#xff0c;人类为了抗击癌症发明了一种药物&#x1f357;&#xff0c;然后给猩猩做了实验&#xff0…
最新文章