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

【Linux系统化学习】进程等待

目录

进程等待

进程等待的必要性

进程等待的方法

wait方法

等待一个进程(阻塞等待) 

waitpid方法

任意等待多个进程(阻塞等待)

父进程获取子进程的退出信息

非阻塞轮询等待


进程等待

进程等待的必要性

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

总结:进程等待就是父进程解决僵尸进程的


进程等待的方法

父进程通过wait/waitpid系统调用来实现

wait方法

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

等待一个进程(阻塞等待) 

#include<stdio.h>2 #include<unistd.h>3 #include<sys/types.h>4 #include<sys/wait.h>5 #include<stdlib.h>6 void Worker()7 {8     int cut =5 ;9     while(cut)10     {11          printf(" am a child process; p    id : %d ppid : %d ,cut : %d \n",getpid(    ),getppid(),cut--);12          sleep(1);13     }14 }15 int main()16 {17     pid_t id = fork();18     if(id==0)19     {20         //child21         Worker();22         exit(0);23     }24     else{25         //father26         sleep(7);27         printf("wait before\n");28        pid_t rid = wait(NULL);29        printf("wait after\n");30         if(rid == id )31         {32             printf("wait success , pid     %d rpid:%d\n",getpid(),rid);33         }34         sleep(2);                      35     }36     return 0;37 }

总结:

  • 父进程通过wait子进程可以回收子进程的僵尸状态
  • 如果子进程没有退出,父进程必须进行阻塞等待(等待软件资源就绪),直接到子进程僵尸,wait回收,返回。
  • 父子进程水仙运行我们不直到是由于调度器决定的,但是我们可以很清楚的直到是父进程最后退出的。

waitpid方法

#include <sys/types.h>
#include <sys/wait.h>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:

  • 0:表示父进程以阻塞的方式等待子进程,即子进程如果处在其它状态,不处在僵尸状态(Z状态),当子进程运行结束,操作系统会检测到,把父进程重新唤醒,然后回收子进程;
  • WNOHANG:非阻塞轮询等待,若 pid 指定的子进程没有结束,处于其它状态,则 waitpid() 函数返回0,不予等待。若正常结束,则返回该子进程的 ID;

任意等待多个进程(阻塞等待)

#include <sys/types.h>    5 #include <sys/wait.h>    6     7 #define N 5     8 void Worker(int i)    9 {    10     int cnt = 5;    11     while(cnt--)    12     {    13         printf("I am child, pid:%d, ppid:%d, %d\n", getpid(), get    ppid(), i);    14         sleep(1);    15     }    16     return;    17 }    18 int main()    19 {    20     int i=0;21     for( i = 0; i < N; i++)    22     {    23         //创建一批子进程24         pid_t id = fork();    25         if(id == 0)26         {27             // child     28             Worker(i);29             exit(0);30         }                                                          31         // father32 33     }34     //等待子进程35     int j=0;36     for(j=0;j<N;j++)37     {38         pid_t rid = waitpid(-1,NULL,0);39         if(rid>0)40         {41             printf("wait %d success\n",rid);42         }43     }

父进程获取子进程的退出信息

在上篇文章进程的终止我们提到,创建进程肯定是完成某一项任务的;任务的结果就三种情况:

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码出异常了,被操作系统发送信号终止

因此,作为父进程通过等待获取这个退出信息;这个信息就是在传入的参数status中被写入。

我们可以看到这个参数的类型是一个整形指针,需要我们在父进程执行的代码块中定义一个整形变量,将这个整型变量取地址作为wait/waitpid的参数交给操作系统,操作系统会将子进程的退出码填充给这个参数。 

  • wait 和 waitpid 都有一个 status 参数,该参数是一个输出型参数,由操作系统填充。

  • 如果传递 NULL,表示不关心子进程的退出状态信息。

  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。

  • status 不能简单的当做整形来看待,可以当做位图来看待,具体细节如下图(只需要关注 status 低16比特位)

 

退出的情况可以总结为两种,正常终止(0:代表成功;非0:代表失败),异常终止; 

前7位代表异常终止时的终止信号,后8位代表我们正常终止的退出状态;

操作系统没有0号信号,因此,如果低七位是0说明子进程没有收到任何信号。

我们要想拿到这两个数字就要进行位运算

  • 退出码:exit_code = (status>>8)&0xFF
  • 信号码: sig_code= (status)& 0x7F

这样的方式非常的麻烦;我们可以使用系统中提供的转化方法获取退出码。

  • WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
  • WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码) 
#include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 #include<sys/types.h>5 #include<sys/wait.h>6 void Worker()7 {8     int cnt = 5;9     while(cnt)10     {11         printf("I am child process,pid: %d,ppid : %d\n,cnt: %d",getpid(),getppid(),cnt--    );12     }13 }14 int main()15 {16     pid_t id = fork();17     if(id == 0)18     {19         //child20         Worker();21        // exit(0);22        exit(10);23     }24     else{25         sleep(10);          26         //father30         int status = 0;31         printf("wait before\n");32        // pid_t rid = wait(NULL );33        pid_t rid = waitpid(id , &status ,0);34 35         printf("wait after\n");36         if(rid==id)37         {38             printf("wait success,pid: %d",getpid());                                                                                                                                    39         }40        // printf("%d\n",status);41        if(WIFEXITED(status))42        {43            printf("child process normal quit , exit code : %d \n",WEXITSTATUS(status));
44        }45        else46        {47            printf("child process quit except!!!\n");48        }49     }50     return 0;51 }

 


非阻塞轮询等待

前面说过如果子进程没有进入僵尸状态,父进程什么也不做就一直阻塞等待子进程。采用非阻塞的方式轮询等待的方式,子进程在没有进程僵尸状态的区间父进程可以进行其他的事情。

 #include<stdio.h>2 #include<stdlib.h>3 #include<unistd.h>4 #include<sys/types.h>5 #include<sys/wait.h>6 void Worker()7 {8     int cnt =3 ;9     while(cnt--)10     {11         printf("am a child  process pid : %d ppid %d num %d \n",getpid(),getppid(),cnt);12         sleep(2);13     }14 }15 int main()16 {17     pid_t id = fork();18     if(id==0)19     {20         //child21         Worker();22         exit(0);23     }24     else25     {26         //father27         while(1)28         {29             pid_t rid = waitpid(id,NULL,WNOHANG );30             if(rid == 0)31             {32                 printf("wait success,but process no quit\n");33                 printf("father process , to do athor thing.......\n");34                 sleep(1);                                                                                                                                                               35             }36             else if(rid < 0)37             {38                 printf("wait fail\n");39                 break;40             }41             else42             {43                 printf("wait success\n");44                 break;45             }46         }47     }48 49     return 0;50 }

第三个参数设置为WNOHONG后,可以通过循环语句控制父进程轮询等待;在子进程未就绪期间父进程可以执行其他的一些简单代码。


 今天对Linux下进程的等待的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!! 

相关文章:

【Linux系统化学习】进程等待

目录 进程等待 进程等待的必要性 进程等待的方法 wait方法 等待一个进程(阻塞等待&#xff09; waitpid方法 任意等待多个进程&#xff08;阻塞等待&#xff09; 父进程获取子进程的退出信息 非阻塞轮询等待 进程等待 进程等待的必要性 之前讲过&#xff0c;子进程退…...

前端学习笔记 | HTML5+CSS3静态网页制作的技巧(持续更新)

注&#xff1a;本文的css样式均使用less写法 1、字体居中 &#xff08;1&#xff09;先text-align:center;行内元素水平居中 &#xff08;2&#xff09;再line-heigh:(盒子高度);行内元素垂直居中 text-align: center;line-height: ( 30 / vw ); 2、盒子居中 情景1&#…...

docker安装-centos

Docker CE 支持 64 位版本 CentOS 7&#xff0c;并且要求内核版本不低于 3.10 卸载旧版本Docker sudo yum remove docker \ docker-common \ docker-selinux \ docker-engine使用yum安装 yum 更新到最新版本: sudo yum update执行以下命令安装依赖包&#xff1a; sudo yum…...

Redis入门指南

文章目录 Redis概述Redis基本数据类型Redis与MySQL的区别以及使用场景如何保持双写一致性&#xff08;缓存一致性&#xff09;1. 延迟双删2. 分布式锁&#xff08;强一致性时使用&#xff09;3. 中间件 Redis持久化机制RDB&#xff08;redis database&#xff09;AOF&#xff0…...

K8s之configMap

1. 概述​ 1.1 什么是configMap​ 1.1 什么是configMap configMap是Kubernetes中的一种资源对象&#xff0c;用于存储配置数据。它可以包含键值对&#xff0c;也可以包含来自文件的配置数据。configMap的作用是将配置数据与应用程序的容器分离&#xff0c;使得配置可以在不重…...

提高 NFS Azure 文件共享性能

本文内容 适用于增加预读大小以提高读取吞吐量Nconnect另请参阅 本文介绍如何提高 NFS Azure 文件共享的性能。 适用于 展开表 文件共享类型SMBNFS标准文件共享 (GPv2)、LRS/ZRS 标准文件共享 (GPv2)、GRS/GZRS 高级文件共享 (FileStorage)、LRS/ZRS 增加预读大…...

【Django-ninja】使用schema

在Django Ninja中&#xff0c;"schema"主要是指帮助描述和规范你的API的工具&#xff0c;以便系统能够自动生成文档并提供验证。通俗地说&#xff0c;它有两个主要作用&#xff1a; API文档生成器&#xff1a; Schema 让 Django Ninja 能够自动生成互动式的API文档。…...

【TCP/IP】用户访问一个购物网站时TCP/IP五层参考模型中每一层的功能

当用户访问一个购物网站时&#xff0c;网络上的每一层都会涉及不同的协议&#xff0c;具体网络模型如下图所示。 以下是每个网络层及其相关的协议示例&#xff1a; 物理层&#xff1a;负责将比特流传输到物理媒介上&#xff0c;例如电缆或无线信号。所以在物理层&#xff0c;可…...

Unity 开发注意事项

1. 空Unity消息 Unity消息被运行时事件调用&#xff0c;即使消息体为空也会被调用。因此&#xff0c;删除空消息避免不必要的处理。 例如&#xff1a; using UnityEngine;class Camera : MonoBehaviour {private void FixedUpdate(){}private void Foo(){} } 应该删除未使用…...

[Unity Sentis] Unity Sentis 详细步骤工作流程

文章目录 1. 导入模型文件支持的模型创建运行时模型导入错误 2. 为模型创建输入将数组转换为张量创建多个输入进行操作 3. 创建一个引擎来运行模型创建一个Worker后端类型 4. 运行模型5. 获取模型的输出获取张量输出多个输出打印输出 1. 导入模型文件 要导入 ONNX 模型文件&am…...

力扣144 二叉树的前序遍历 Java版本

文章目录 题目描述递归方法代码 非递归方法代码 题目描述 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xf…...

《Vue3 基础知识》 使用 GoGoCod 升级到Vue3+ElementPlus 适配处理

此篇为 《Vue2ElementUI 自动转 Vue3ElementPlus&#xff08;GoGoCode&#xff09;》 的扩展&#xff01; Vue3 适配 Vue3 不兼容适配 Vue 3 迁移指南 在此&#xff0c;本章只讲述项目或组件库中遇到的问题&#xff1b; Vue3 移除 o n &#xff0c; on&#xff0c; on&#…...

c#string方法对比

字符串的截取匹配操作在开发中非常常见&#xff0c;比如下面这个示例&#xff1a;我要匹配查找出来字符串数组中以“abc”开头的字符串并打印&#xff0c;我下面分别用了两种方式实现&#xff0c;代码如下&#xff1a; using System; namespace ConsoleApp23{ class Progra…...

Electron实战(一):环境搭建/Hello World/打包exe

文章目录 Electron安装Node.jsNodeJs推荐配置开始Electron项目创建index.js文件创建src目录运行打包生成exe生成安装包踩坑 下一篇Electron实战(二)&#xff1a;将Node.js和UI能力&#xff08;app/BrowserWindow/dialog)等注入html Electron Electron是一个使用JavaScript, HT…...

【C++】运算符重载详解

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读 1. 为什么需要运算符重载 2. 运算符重载概念 3. 运算符重载示例 3.1 运算符重载 3.2 >或<运算符 4. 运算符重…...

评论区功能的简单实现思路

评论区功能是社交类项目中的核心组成部分&#xff0c;它涉及到前端的交云和后端的数据处理。基于你的技术栈&#xff08;前端 Vue3&#xff0c;后端 Java&#xff09;&#xff0c;下面是一个具体的实现思路和数据库设计建议&#xff0c;并探索一下知乎的评论系统。 数据库设计…...

Java自救手册

目录 访问地址 访问地址&#xff0c;发现不通&#xff0c;无法访问&#xff1a; 网络不通一般有两种情况&#xff1a; Maven 拿Maven 拿到Maven以后 Maven单独的报红 Git git注意&#xff1a; 目录 访问地址 访问地址&#xff0c;发现不通&#xff0c;无法访问&…...

ASM-HEMT参数提取和模型验证测试

参数提取程序 直流I-V参数提取 DC模型参数提取流程对于ASM-GaN-HEMT模型可以总结在下图中。 以下步骤描述了该流程&#xff1a; 在模型中设置物理参数&#xff0c;如L&#xff08;沟道长度&#xff09;、W&#xff08;沟道宽度&#xff09;、NF&#xff08;栅指数&#xf…...

浅压缩、深压缩、双引擎、计算机屏幕编码……何去何从?

专业视听领域尤其显示控制和坐席控制领域&#xff0c;最近几年最激动人心的技术&#xff0c;莫过于分布式了。 分布式从推出之日就备受关注&#xff1a;担心稳定性的&#xff0c;质疑同步性能的&#xff0c;怀疑画面质量的…… 诚然&#xff0c;我们在此前见多了带着马赛克的…...

2020年通信工程师初级专业实务真题

文章目录 一、第1章 现代通信网概述&#xff1a;信令网、同步网、管理网。第10章 通信业务&#xff1a;通信产业链&#xff0c;通信终端的分类&#xff0c;通信业务的定义及分类二、第3章 接入网&#xff1a;无线接入网的优点&#xff0c;接入网的接口&#xff08;UNI&#xff…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

区块链技术概述

区块链技术是一种去中心化、分布式账本技术&#xff0c;通过密码学、共识机制和智能合约等核心组件&#xff0c;实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点&#xff1a;数据存储在网络中的多个节点&#xff08;计算机&#xff09;&#xff0c;而非…...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

书籍“之“字形打印矩阵(8)0609

题目 给定一个矩阵matrix&#xff0c;按照"之"字形的方式打印这个矩阵&#xff0c;例如&#xff1a; 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为&#xff1a;1&#xff0c;…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...