【Linux详解】进程等待 | 非阻塞轮询

news2024/11/25 4:48:26

引入

为什么?是什么?怎么办

是什么?

进程等待是指父进程暂停自己的执行,直到某个特定的子进程结束或发生某些特定的事件。

为什么?

  • 僵尸进程刀枪不入,不可被杀死,存在内存泄露
  • 获取进程的执行情况,知道我布置给子进程的任务,它完成的怎么样了–可选

怎么办

wait 函数

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

pid_t wait(int* status);

测试:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
 
int main (
    void
    ) 
{
    pid_t id = fork();
    if (id == 0) {
        // child
        while (1) {
            printf("我是子进程,我正在运行... Pid: %d\n", getpid());
            sleep(1);
        }
    }
    else {
        printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid());
        sleep(20);   // 为了便于观察,我们让父进程休眠20s
 
        // 苏醒后,父进程执行 wait,耐心地等待子进程
        pid_t ret = wait(NULL);  // 暂且将status参数设置为NULL
        if (ret < 0) {
            printf("等待失败!\n");
        }
        else {
            printf("等待成功!\n");   // 此时 Z → X
        }
 
        sleep(20);  // 子进程退出后,再让父进程存在一段时间
    }
}

在这里插入图片描述

为什么是交替型,不是一个执行完?//了解循环的细节

fork 创建子进程后,父进程会首先执行并打印这条信息,其中 <父进程的pid> 是父进程的进程ID。截不下就没截了

  • 父进程打印一次消息后休眠20秒:
    • 父进程仅在创建子进程后打印一次消息,然后休眠20秒等待观察子进程的活动,不再进行其他操作。

通过这种方式,父进程和子进程能够并发地执行各自的任务,并且我们通过延迟父进程的退出能观察到子进程的连续活动。

整个程序执行流程如下:
  1. 父进程打印:

    yamlCopy code
    我是父进程: pid: 1234,我将耐心地等待子进程!
    
  2. 子进程每秒打印一次:

    yamlCopy code
    我是子进程,我正在运行... Pid: 5678
    

    (此循环持续到子进程被终止)

  3. 通过终端输入 kill 5678 终止子进程。

  4. 父进程20秒后苏醒并等待子进程结束后,打印:

    textCopy code
    等待成功!
    

之后,父进程再休眠20秒并继续存在一段时间后退出


waitpid

刚才讲的 wait 并不是主角,因为其功能比较简单,在进程等待时用的更多的是 waitpid

waitpid 可以把 wait 完全包含,wait 是 waitpid 的一个子功能。

参数

  • pid
    

    :要等待的子进程的进程ID。根据传入的值可以指定等待任何子进程、特定进程ID的子进程、任何同一进程组的子进程或者任何同一会话的子进程。

    • 如果 pid 大于零,waitpid 将等待指定进程ID的子进程结束。
    • 如果 pid 等于 -1,waitpid 将等待任意子进程结束,等同于 wait 函数。
  • status:一个指向整型的指针,是一个输出型参数,它将用于存储子进程的终止状态

  • options
    

    :用于指定等待行为的附加选项。

    • 传入0表示以默认行为等待子进程。(阻塞等待中再讲)

返回值

  • 如果 waitpid 成功,返回值是已终止子进程的进程ID
  • 如果出现错误,返回-1,并且会设置 errno 变量来指示具体错误原因。

Z状态,其本质上就是将自己的 task_struct 维护起来(代码可以释放,但是 task_struct 必须维护)。所谓的 wait/waitpid 的退出信息,实际上就是从子进程的 task_struct 中拿出来的,即 从子进程的 task_struct 中拿出子进程退出的退出码,拷贝到父进程中

在这里插入图片描述

status

该参数是一个 输出型参数 (即通过调用该函数,从函数内部拿出来特定的数据)。整数的低 16 位,其中又可以分为 最低八位次低八位(具体细节看图):

img

1.次低八位:拿子进程退出码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
 
int main (
    void
    ) 
{
    pid_t id = fork();
    if (id == 0) {
        int cnt = 5;   // 循环5次
        // child
        while (1) {
            // 五秒之内运行状态
            printf("我是子进程,我正在运行... Pid: %d\n", getpid());
            sleep(1);
 
            // 五秒之后子进程终止
            cnt--;
            if (cnt == 0) {
                break; 
            }
        }
 
        exit(233);   // 方便辨识,退出码我们设置为233,这是我们的预期结果
    }
    else {
        printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid());
        
        // ***** 使用waitpid进行进程等待
        int status = 0;  // 接收 waitpid 的 status 参数
 
        pid_t ret = waitpid(id, &status, 0);
        if (ret > 0) {   // 等待成功
            printf (
                "等待成功,ret: %d, 我所等待的子进程退出码: %d\n", 
                ret,
                (status>>8)&0xFF
            );
        }
 
    }
}

status 并不是整体使用的,而是区域性使用的,我们要取其次低八位。我们可以用 位操作 来完成,将 status右移八位再按位与上 0XFF,即 (status>>8)&0xFF ,就可以提取到 status 的次低八位了。

在这里插入图片描述

waitpid 经过系统调用,来读取子进程的pcb(eg. task_st…),这是为什么呢

操作系统不相信任何人,父进程用户无法直接读取子进程的 pcb ,要通过系统调用的接口

在这里插入图片描述

2.初识 core dump(核心转储)

在这里插入图片描述

它是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。目前只需要知道,该信息是用于调试的。

3.最低七位:提取子进程的退出信号

刚才我们讲的 wait/waitpid 和次低八位的时侯,都是关于进程(exit) 的 正常退出。

如果进程 异常退出 呢?我们来模拟一下进程的异常退出。

💬 模拟异常退出的情况,让子进程一直跑,父进程一直等。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
 
int main (
    void
    ) 
{
    pid_t id = fork();
    if (id == 0) {
        // 子进程一直不退出,父进程会一直等待。
        // child
        while (1) {
            printf("我是子进程,我正在运行... Pid: %d\n", getpid());
            sleep(1);
        }
 
        exit(13);
    }
    else {
        printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid());
        
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if (ret > 0) {   // 等待成功
            printf(
                "等待成功,ret: %d, 我所等待的子进程退出码: %d\n, 退出信号是: %d", 
                ret, (status>>8)&0xFF, 
                status&0x7F
            );
        }
 
    }
}

现在我们直接 while(1) 死循环让子进程往死里跑,此时父进程由于调用了 waitpid,就会一直等待子进程,父进程就会持续阻塞

父进程看到子进程kill了,终于可以不用等了,可以给子进程收尸了

在这里插入图片描述

可以发现,使用-9号信号kill掉进程时,进程的退出信号就是9,然而当进程由于信号异常终止时,此时进程退出码是无意义的!

所以进程的等待可以理解为是 父进程在等给子进程退出记录


非阻塞轮询

options ->阻塞方式

waitpid(pid,&status,WNOHANG);

WNOHANG就是wait no hang,hang也就是悬挂,也就是非阻塞,等待子进程死亡,若父进程执行到waitpid时,子进程还没退出,则函数返回0后接着运行下面的代码,若执行到waitpid后子进程已经退出则返回退出子进程的pid

假如要期末考试了,我想找小张去自习室帮我复习,小张自己也在复习,我打电话问他什么时候复习完了,可以出门,情况解释如下

WNOHANG 夯住,非阻塞+循环

我给小张间隔打电话寻求帮忙,自己干等在楼下

阻塞式调用

打电话一直不挂

非阻塞轮询+自己的事情(最高效)

间隔打电话,自己也在复习

在这里插入图片描述

返回值

pid_t

ret_pid=0–所等待的条件还没有就绪,>0成功返回退出码,<0失败

代码验证

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    pid_t id = fork();
    if(id<0)
    {
        perror("fork");
        exit(1);
    }

    if(id==0)//子进程代码
    {
        int count = 5;
        while(count)
        {
            printf("[%d]我是子进程,我的pid是: %d\n",count,getpid());
            sleep(1);
            count--;
        }
        exit(55);//子进程执行完代码后退出
    }
    //父进程代码
    while(1)//循环访问子进程退出情况
    {
        int wait = waitpid(id,NULL,WNOHANG);
        if(wait>0)//子进程退出成功
        {
            printf("子进程退出成功,子进程pid: %d\n",wait);
            break;
        }
        else if(wait==0)//子进程还没退出,父进程干自己的事情
        {
            //此处简单模拟父进程干的事情
            printf("我是父进程,我现在要干一些别的事情\n");
        }
        else //等待子进程退出失败
        {
            perror("waitpid");
            exit(1);
        }
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

⚠️注:这里父进程可以执行任一任务,我使用printf打印,只是为了明显的看到父进程是没有阻塞等待的!


进程退出的宏

为了增加可读性,定义了接口宏,来查找退出码

WEXITSTATUS WIFEXITED,在这之前,我们再思考一个问题:

❓ **思考:**一个进程退出时,可以拿到退出码和推出信号,我们先看谁?

一旦程序发现异常,我们只关心退出信号,退出码没有任何意义。

所以,我们先关注退出信号,如果有异常了我们再去关注退出码。

WEXITSTATUS 宏用于查看进程的退出码,若非 0,提取子进程退出码。

WEXITSTATUS(status)

WIFEXITED 宏用于查看进程是否正常退出,如果是正常终止的子进程返回状态,则为真。

WIFEXITED(status)

waitpid意义:

  1. 返回记录子进程内核的数据结构

  2. Z->X

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Codeforces Round 918 (Div. 4)(A~F)

目录 A. Odd One Out B. Not Quite Latin Square C. Can I Square? D. Unnatural Language Processing E. Romantic Glasses F. Greetings A. Odd One Out Problem - A - Codeforces 输出一个不同于其他两个数的数&#xff0c;用异或操作可以轻松解决。 void solve{int…

ompl.app的demo_OpenDEPlanning例子

编译了下OMPL和OMPL.app, 其中有个example 是用刚体动力学库ODE搭建的小车运动场景&#xff0c;找出小车到目标的路径&#xff0c;牵引小车跑到目标位置。 ompl小车路径运动模拟

https 自签证书相关生成csr文件、p12文件、crt文件、jks文件、key文件、pem文件

文章目录 前言https 自签证书相关生成csr文件、p12文件、crt文件、jks文件、key文件、pem文件1, 检查openssl的版本2. 生成私钥和证书签署请求 (CSR)3. 生成自签名证书4. 将证书和私钥转换为 PKCS12 格式的密钥库5. 创建信任库 (Truststore)6. 将 PKCS12 文件转换为 JKS 文件7.…

详解Python递归解决汉诺塔问题

Python递归解决汉诺塔问题 递归解决汉诺塔问题是经典的计算机科学问题&#xff0c;它涉及到如何将一堆盘子从一个柱子上移动到另一个柱子上&#xff0c;每次只能移动一个盘子&#xff0c;并且大盘子不能放在小盘子上面。 例如我们需要将a柱盘子全部移动到b柱&#xff0c;接下来…

程序员熬夜看欧洲杯被“冻住”,呼吸困难……

2024欧洲杯接近尾声&#xff0c;更是激发球迷兴趣。由于时差关系&#xff0c;很多球迷熬夜看球&#xff0c;啤酒、宵夜成了标配。然而&#xff0c;在这份欢乐背后&#xff0c;也隐藏着健康风险。 日前&#xff0c;浙江杭州29岁的程序员单先生熬夜与朋友看完球赛后开车回家&…

室内定位可视化:精准导航与实时位置展示

通过图扑室内定位可视化技术&#xff0c;提供精准的导航服务和实时位置展示&#xff0c;帮助用户高效找到目标地点&#xff0c;提升空间管理和资源配置的效率与体验。

Spring学习05-[AOP学习-AOP原理和事务]

AOP原理和事务 AOPAOP底层原理比如下面的代码案例手动模拟AOP 动态代理详解JDK动态代理 AOP AOP底层原理 当实现了AOP,Spring会根据当前的bean创建动态代理(运行时生成一个代理类) 面试题&#xff1a;为什么执行方法的时候&#xff0c;会执行切面里的通知方法&#xff1f; 比…

51单片机嵌入式开发:1、STC89C52环境配置到点亮LED

STC89C52环境配置到点亮LED 1 环境配置1.1 硬件环境1.2 编译环境1.3 烧录环境 2 工程配置2.1 工程框架2.2 工程创建2.3 参数配置 3 点亮一个LED3.1 原理图解读3.2 代码配置3.3 演示 4 总结 1 环境配置 1.1 硬件环境 硬件环境采用“华晴电子”的MINIEL-89C开发板&#xff0c;这…

YOLOv8 | 代码逐行解析(五) | YOLOv8中损失函数计算的详解包含Cls和Bbox计算的解析,小白必看(下)

一、本文介绍 本文给大家带来的是YOLOv8中的损失函数计算的完整解析&#xff0c;内容包括v8DetectionLoss的解析&#xff0c;以及BboxLoss的解析&#xff0c;如果你相对损失函数的计算原理&#xff0c;本文内容绝对会对你有所帮助&#xff0c;全文内容包含1万两千字&#xff0…

【鸿蒙学习笔记】MVVM模式

官方文档&#xff1a;MVVM模式 [Q&A] 什么是MVVM ArkUI采取MVVM Model View ViewModel模式。 Model层&#xff1a;存储数据和相关逻辑的模型。View层&#xff1a;在ArkUI中通常是Component装饰组件渲染的UI。ViewModel层&#xff1a;在ArkUI中&#xff0c;ViewModel是…

四大常见的排序算法JAVA

1. 冒泡排序 相邻的元素两两比较&#xff0c;大的放右边&#xff0c;小的放左边 第一轮比较完毕之后&#xff0c;最大值就已经确定&#xff0c;第二轮可以少循环一次&#xff0c;后面以此类推 如果数组中有n个数据&#xff0c;总共我们只要执行n-1轮的代码就可以 package Bu…

转盘输入法-键盘加鼠标版本

序 转盘输入法&#xff0c;给你的聊天加点新意。它不用常见的九宫格或全键盘&#xff0c;而是把字母摆在圆盘上&#xff0c;一滑一滑&#xff0c;字就出来了&#xff0c;新鲜又直接。 键盘加鼠标版本GIF演示 演示软件下载 转盘输入法PC演示版本EXE下载https://download.csdn…

一招解决找不到d3dcompiler43.dll,无法继续执行代码问题

当您的电脑遇到d3dcompiler43.dll缺失问题时&#xff0c;首先需要了解d3dcompiler43.dll文件及其可能导致问题的原因&#xff0c;之后便可以选择合适的解决方案。在此&#xff0c;我们将会为您提供寻找d3dcompiler43.dll文件的多种处理方法。 一、d3dcompiler43.dll文件分析 d…

virtualbox安装unbuntu22.04

准备 virtualbox https://www.virtualbox.org/ ubuntu ios https://ubuntu.com/ 安装 等待安装结束即可&#xff0c;输入账号密码登录系统 远程连接发现失败&#xff0c;不过ping 外网可以访问 关闭虚拟机&#xff0c;选择工具&#xff0c;网络查看ip 选择虚拟机&#…

【初中数学选讲】绝对值的几何意义例题(20240503-01)

初中数学选讲&#xff1a;绝对值的几何意义例题&#xff08;20240503-01&#xff09; 1. 练习题目1.1 题目描述1.2 分析 2 答题2.1 定义2.2 分段讨论2.2.1 情况1&#xff1a; x x x点在 a a a点左侧&#xff08; x < a , m ∣ x − a ∣ x<a,\ \ m\left|x-a\right| x<…

数字时代的影像奇迹:专业照片处理软件的创新功能与视觉盛宴

大家好&#xff01;随着时间的流逝&#xff0c;一些珍贵的照片可能会因各种原因而变得模糊不清&#xff0c;但幸运的是&#xff0c;现代科技的发展为我们提供了一种解决方案——专业的照片处理软件。这类软件具备强大的功能&#xff0c;能够将照片高清修复并赋予特效变化&#…

Elasticsearch:Runtime fields - 运行时字段(二)

这是继上一篇文章 “Elasticsearch&#xff1a;Runtime fields - 运行时字段&#xff08;一&#xff09;” 的续篇。 目录 在查询时覆盖字段值 检索运行时字段 定义运行时字段以计算星期几 提取一些数据 搜索计算出的星期几 从相关索引中检索字段 索引运行时字段 使用运…

在门店里造绿色氧吧!康养行业也这么卷了?

拼啥不如拼健康&#xff0c;现在的人算是活明白了&#xff0c;不但中老年人这样想&#xff0c;年轻人也这样干。你可能不知道&#xff0c;现在众多健康养生门店&#xff0c;逐渐成了年轻人“组团养生”的好去处&#xff0c;也是他们吃喝玩乐之外的新兴消费趋势。 而在看得见的…

L04_MySQL知识图谱

这些知识点你都掌握了吗&#xff1f;大家可以对着问题看下自己掌握程度如何&#xff1f;对于没掌握的知识点&#xff0c;大家自行网上搜索&#xff0c;都会有对应答案&#xff0c;本文不做知识点详细说明&#xff0c;只做简要文字或图示引导。 1 基础 1.1内部组件结构 1.2 数据…

自注意力机制和多头注意力机制区别

Ref&#xff1a;小白看得懂的 Transformer (图解) Ref&#xff1a;一文彻底搞懂 Transformer&#xff08;图解手撕&#xff09; 多头注意力机制&#xff08;Multi-Head Attention&#xff09;和自注意力机制&#xff08;Self-Attention&#xff09;是现代深度学习模型&#x…