Linux 进程(九) 进程等待

        子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏,所以父进程回收子进程是必然要做的。
        另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
        最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。
        父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息(子进程退出的信息包括进程退出码,我进程推出时候的信号)。

        进程等待的方法:

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

        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。

        下面通过一个小代码来验证:wait

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>int main()
{pid_t id = fork();if(id == 0){int cnt = 5;while(cnt--){printf(" i am child procrss,pid:%d,ppid:%d\n",getpid(),getppid());sleep(1);}printf("子进程退出\n");exit(1);}printf("父进程开始休眠,等待子进程\n");sleep(10);printf("父进程开始回收\n");pid_t rid = wait(NULL);if(rid > 0){printf("wait success,rid:%d\n",rid);}printf("父进程回收结束\n");sleep(3);return 0;
}

        该代码,总共运行十三秒,前五秒父进程子进程一起运行,前五秒过后子进程退出。中间五秒父进程等待回收子进程,这时会看到子进程僵尸的状态,中间五秒后,父进程回收子进程。最后三秒,父进程休眠三秒,然后程序退出。

        注意:fork之后,父进程和子进程谁先运行是不确定的,由调度器说了算。

        修改一下代码,使用waitpid。

        

        通过上文对waitpid的描述,第一个参数传id,是子进程的id。第二个参数传递一个地址,这个记录进程退出时的退出码和收到的信号,第三个参数设置为0表示阻塞等待。

 

        通过上图我们可以看出,进程推出的退出状态时status = 256 。那么时为什么呢?

        status是一个整形,有三十二个bit位,前16个bit位不用,后十六个bit位的前八位表示进程退出时的退出码,后七位表示进程退出时收到的信号。子进程退出时设置的时exit(1),故而经过转化,得到的status是256。

        如果想直接拿到信号编号和进程退出码,还可以这样写。

printf("wait success! rid:%d , status:%d,exit singno:%d, exit code:%d\n",rid,status,status&0x7F,(status>>8)&0xFF);

        这样显示的就比较直观了。

       如果不想着麻烦的话,Linux系统同时给我们提供了两个宏让我们可以直接提取到进程的退出码。

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

        用法如下:

  if(WIFEXITED(status)){
printf("wait success! rid:%d , status:%d,exit code:%d\n",rid,status,WEXITSTATUS(status));} 

        

        同时waitpid的第三个参数设置为0表示阻塞调用,而设置为WNOHANG 表示非阻塞调用。

        阻塞调用表示:父进程一直等待当前子进程到结束,然后读取返回的退出码以及信号。

        非阻塞调用表示:父进程基于非阻塞的轮询访问子进程,访问一次子进程发现没有结果,然后就返回,不必等到子进程有结果才返回。其间父进程也可以去执行别的代码,而不是一直卡住等待子进程有结果。

        注意:为什么我们不能自己定义一个变量,子进程退出修改这个变量,然后给父进程呢?

        答案是不行的,进程间具有独立性。父进程创建子进程,当子进程对数据做修改时会发生写时拷贝。子进程的信息属于内核数据,父进程读取子进程属于读取内核数据,而操作系统不相信任何人,所以只能通过系统调用来读取。同时,用户定义的变量属于用户层面的,而子进程的信息属于内核数据,子进程不能直接对用户层面的信息做修改,还是要通过系统调用。

        下面是一个代码演示了基于非阻塞轮询访问子进程,其间父进程也可以执行别的代码。

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>#define NUM 5
typedef void(*fun_t)();
fun_t task[NUM];void printflog()
{printf("this is log task\n");
}void printfnet()
{printf("this is net task\n");
}void printfnpc()
{printf("this is npc task\n");
}void inittask()
{task[0] = printflog;task[1] = printfnet;task[2] = printfnpc;task[3] = NULL;
}void excutetask()
{for(int i = 0;task[i];i++) task[i]();
}int main()
{inittask();pid_t id = fork();if(id == 0){int cnt = 5;while(cnt){printf("i am child process,pid:%d ,ppid:%d\n",getpid(),getppid());sleep(1);cnt--;}exit(111);}int status = 0;while(1){pid_t rid = waitpid(id,&status,WNOHANG); if(rid > 0){printf("wait success! rid:%d , status:%d,exit  code:%d\n",rid,status,WEXITSTATUS(status));break;}else if(rid == 0){printf("father say: child is runnin,do other thing\n");printf("##################begin######################\n\n");excutetask();printf("##################end######################\n");}else{perror("waitpid");break;}sleep(1);}return 0;
}

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

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

相关文章

googlecode.log4jdbc慢sql日志,格式化sql

前言 无论使用原生JDBC、mybatis还是hibernate&#xff0c;使用log4j等日志框架可以看到生成的SQL&#xff0c;但是占位符和参数总是分开打印的&#xff0c;不便于分析&#xff0c;显示如下的效果: googlecode Log4jdbc 是一个开源 SQL 日志组件&#xff0c;它使用代理模式实…

day06、SQL语言之概述

SQl 语言之概述 6.1 SQL语言概述6.2 SQL语言之DDL定义数据库6.3 SQL语言之DML操纵数据库 6.1 SQL语言概述 6.2 SQL语言之DDL定义数据库 6.3 SQL语言之DML操纵数据库

BLE Mesh蓝牙组网技术详细解析之Foundation Model Layer基础模型层(七)

目录 一、什么是BLE Mesh Foundation Model Layer基础模型层&#xff1f; 二、模型 2.1 配置模型 2.2 健康模型 三、状态 3.1 Composition Data 四、资料获取 一、什么是BLE Mesh Foundation Model Layer基础模型层&#xff1f; BLE Mesh Foundation model Layer是蓝牙…

redis服务迁移数据工具--RDM

一、背景&#xff1a; 在日常的运维工作经常遇见各种数据迁移工作&#xff0c;例如mysql数据库迁移、redis数据库迁移、minio数据迁移等等工作。这里介绍一下redis数据库的迁移过程。 二、迁移思路&#xff1a; redis服务/集群的数据迁移思路是需要新建一个配置、密码一样的re…

【Leetcode】2487. 从链表中移除节点

文章目录 题目思路代码 题目 2487. 从链表中移除节点 思路 1、递归移除节点&#xff1a; 如果头节点为空&#xff0c;直接返回空。递归调用函数处理下一个节点 head->next。在递归返回后&#xff0c;判断当前节点的值是否小于之前记录的最大值 maxVal。如果小于 maxVal…

洛谷p1829(莫比乌斯反演)

思路&#xff1a; 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const double eps 1e-8; const int N 1e710; const long long mod 20101009…

【鸿蒙】安装DevEco Studio运行HarmonyOS第一个APP(小白必看)

文章目录 前言一、DevEco Studio是什么&#xff1f;二、DevEco Studio安装运行1. 下载DevEco Studio2. 安装DevEco Studio3. 启动DevEco Studio4. 运行APP5. 修改代码 三、DevEco Studio调试注意事项总结 前言 鸿蒙OS是华为公司开发的一款基于微内核、耗时10年、4000多名研发人…

MySQL检索距离当前最近的7个小时内,靠近每个时间点数据信息

MySQL检索距离当前最近的7个小时内&#xff0c;靠近每个时间点数据信息 如果你想在最近7个小时内找到每个时间点最接近的数据&#xff0c;即使某些时间点没有数据&#xff0c;你可以使用子查询和窗口函数。以下是一个示例查询&#xff1a; sqlCopy codeSELECTt.time_point,CO…

集群渲染是?渲染农场是?两者与云渲染关联是什么

在数字化浪潮不断推进的当下&#xff0c;渲染技术在多个行业中发挥着至关重要的作用&#xff0c;尤其体现在电影制作、建筑可视化以及电子游戏开发等领域。在众多渲染技术中&#xff0c;集群渲染、渲染农场以及云渲染特别受到业界的重视。本文旨在阐述这些概念的含义以及它们之…

基于SpringBoot的在线考试系统源码和论文

网络的广泛应用给生活带来了十分的便利。所以把在线考试管理与现在网络相结合&#xff0c;利用java技术建设在线考试系统&#xff0c;实现在线考试的信息化管理。则对于进一步提高在线考试管理发展&#xff0c;丰富在线考试管理经验能起到不少的促进作用。 在线考试系统能够通…

osg-材质 (osg::Material)

1.材质类 材质类 (osg::Material)继承自osg::StateAttribute 类。osg::Material 封装了 OpenGL的 glMaterial()和glColorMaterial()指令的函数功能&#xff0c;其继承关系图如图5-27 所示。 图 5-27 osg::Material 的继承关系图 在场景中设置节点的材质属性&#xff0c;首先要…

DBSCAN聚类算法

DBSCAN读作&#xff1a;DB Scan&#xff0c;是英语基于密度的噪声应用空间聚类&#xff08;Density-Based Spatial Clustering of Applications with Noise&#xff09;的简写。在理解K-means聚类算法之后再来理解DBSCAN就容易多了。 DBSCAN的步骤如下&#xff1a; 随机从一个…

年终特辑 | 2023卓翼飞思答卷,诚邀您共同翻阅...

朝夕轮转 , 岁序更替&#xff0c;站在岁末&#xff0c;回首2023 &#xff0c;汇成的每一帧都有迹可循 &#xff1b;卓翼飞思实验室产品升级、技术创新、服务卓越、勇毅前行以抢拼实干兑现硕果&#xff01;无论您是亲历者&#xff0c;还是见证者&#xff0c;我们在此诚邀您共同翻…

高效工具汇总,让学习和办公飞起来

目录 1、寻找论文&#xff0c;效率很高2、学习各类编程的地方 1、寻找论文&#xff0c;效率很高 AMiner&#xff0c;由清华大学计算机科学与技术系的唐杰教授团队开发的一个显著的学术搜索和挖掘系统。系统提供了一整套功能以协助学术研究&#xff0c;包括研究人员档案、专家搜…

element-ui Tree 树形控件 过滤保留子级并获取过滤后的数据 多选改单选

本示例基于vue2 element-ui element-ui 的官网demo是只保留到过滤值一级的&#xff0c;并不会保留其子级 目标 1、Tree 树形控件 保留过滤值的子级 2、在第一次过滤数据的基础上进行第二次过滤 3、Tree 树形控件 多选改为单选&#xff0c;且只有最末端子级可以选择 不足…

Django 8 通用视图基础

1. 什么是通用视图 1. 在terminal 输入 django-admin startapp the_12回车 2. tutorial\settings.py 注册 INSTALLED_APPS [django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.sta…

链接器--动态链接器--延迟绑定与动态链接器是什么?学习笔记二

内容在下面链接&#xff08;通过新建标签页打开&#xff09;&#xff1a; 链接器--动态链接器--延迟绑定与动态链接器是什么&#xff1f;学习笔记二一个例子来看延迟加载https://mp.weixin.qq.com/s?__bizMzkyNzYzMjMzNA&mid2247483713&idx1&snee90a5a7d59872287…

C++知识切片①:运算符重载之前置递增和后置递增

文章目录 前置递增的实现1.先写好main函数及头文件2.自定义MyInteger类3.重定义cout4.在类内实现前置递增 后置递增的实现完整代码 在进行运算符重载之前&#xff0c;不妨先看看常规的前置递增和后置递增的区别&#xff1a; 前置递增如a所示&#xff0c;a是先进行递增计算&…

人工智能大模型:定义、发展和应用

⭐简单说两句⭐ ✨ 正在努力的小新~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &…

k8s中的容器探针

pod的容器健康检查---探针 probe&#xff1a;k8s对容器执行的定期检查&#xff0c;诊断。 探针的三种规则 所有的探针都是针对容器不是针对pod 1、 存活探针---livenessProbe&#xff1a;探测容器是否正常运行。如果发现探测失败&#xff0c;会杀掉容器。容器会根据重启策略…