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

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

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

相关文章

C++泛编程(3)

类模板基础 1.类模板的基本概念2.类模板的分文件编写3.类模板的嵌套 &#xff08;未完待续...&#xff09; 在往节内容中&#xff0c;我们详细介绍了函数模板&#xff0c;这节开始我们就来聊一聊类模板。C中&#xff0c;类的细节远比函数多&#xff0c;所以这个专题也会更复杂。…

Python实战:爬取小红书

有读者在公众号后台询问爬取小红书&#xff0c;今天他来了。 本文可以根据关键词&#xff0c;在小红书搜索相关笔记&#xff0c;并保存为excel表格。 爬取的字段包括笔记标题、作者、笔记链接、作者主页地址、作者头像、点赞量。 一、先看效果 1、爬取搜索页 2、爬取结果保存到…

【蓝桥杯冲冲冲】动态规划学习 [NOIP2003 提高组] 加分二叉树

【蓝桥杯冲冲冲】动态规划学习 [NOIP2003 提高组] 加分二叉树 蓝桥杯备赛 | 洛谷做题打卡day24 文章目录 蓝桥杯备赛 | 洛谷做题打卡day24[NOIP2003 提高组] 加分二叉树题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示数据规模与约定思路 题解代码我的一些话 [NOI…

【鸿蒙】大模型对话应用(四):页面发起请求实现对话能力

Demo介绍 本demo对接阿里云和百度的大模型API&#xff0c;实现一个简单的对话应用。 DecEco Studio版本&#xff1a;DevEco Studio 3.1.1 Release HarmonyOS SDK版本&#xff1a;API9 关键点&#xff1a;ArkTS、ArkUI、UIAbility、网络http请求、列表布局、层叠布局 定义接…

JAVA-File五个练习

下面习题思路大多都是&#xff1a; 1.获取路径下所有列表&#xff08;listfiles&#xff09;&#xff0c;2.遍历文件或文件夹&#xff08;增强for&#xff09;&#xff0c;3.判断是否是文件&#xff08;isFile&#xff09;并直接执行逻辑&#xff0c;4.判断当前是文件夹的情况&…

oc云渲染云渲染操作步骤

随着技术的飞速进步&#xff0c;云渲染已经日益成为一个主流的渲染选择。OC云渲染以其高效率、易用性和可靠性获得了广泛的认可和喜爱。尽管如此&#xff0c;对于刚入门的用户而言&#xff0c;掌握OC云渲染的正确方法可能仍旧是一项挑战。接下来&#xff0c;我们会详尽解释OC云…

vivado 手动设置自下而上的流量并导入网表、创建较低级别的网表

手动设置自下而上的流量并导入网表 要手动运行自下而上的流&#xff0c;请将较低级别的网表或第三方网表实例化为黑色盒子&#xff0c;Vivado工具在合成完成后将黑盒子融入完整的设计中。这个以下部分描述了该过程。 重要&#xff01;Vivado合成不合成或优化加密或非加密合成…

使用_NT_SYMBOL_PATH在启动VS前设置PDB路径

一、背景 由于公司相关项目的开发管理方式&#xff0c;导致公司会存在多个分支的版本正在开发/测试中。 在这样的背景下&#xff0c;我的日常工作中有时会出现存在某个分支的项目软件的某个功能出现了问题需要我去排查解决&#xff0c;而我当前并不在该分支上开发。于是只能安装…

AI重构千行百业!超声波俱乐部大湾区内部分享会圆满落幕

1月27日、28日&#xff0c;超声波俱乐部内部分享会第十六期、第十七期分别在深圳、广州召开&#xff0c;创梦天地、元气森林、新浪智库、百准、A2空间对活动进行了特别支持&#xff0c;六十余名AI领域的创始人和行业嘉宾出席分享会。 出席活动的嘉宾有&#xff1a; 超声波创始…

Kubernetes operator(五)api 和 apimachinery 篇

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Kubernetes operator学习 系列第五篇&#xff0c;主要对 k8s.io/api 和 k8s.io/apimachinery 两个项目 进行学习基于 kubernetes v1.24.0 代码分析Kubernetes operator学习系列 快捷链接 Kubernetes operator&a…

C++进阶(十)哈希的应用——位图布隆过滤器

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、位图1、位图概念2、位图的实现3、位图的应用 二、布隆过滤器1、布隆过滤器提出2、布隆过滤…

通过html2canvas和jsPDF将网页内容导出成pdf

jsPDF参考&#xff1a;https://github.com/parallax/jsPDF html2canvas参考&#xff1a;https://github.com/niklasvh/html2canvas 或者 https://html2canvas.hertzen.com 思路 使用html2canvas将选中DOM生成截图对象将截图对象借助jsPDF导出为PDF文件 代码 这是一个示例&a…