进程终止和进程等待

一 进程终止

        (1)exit和return 

        先前已经了解了进程创建,以及进程大致相关的数据结构,但是有个小知识一直没提及,那就是exit,还有就是return 0。这两个的作用有点相似,都可以终止进程,但又有点不同,例如return 只有在main函数内才可以结束进程,而exit在任意地方都可以结束进程。

终止场景

1:代码正确跑完,结果正确

2:  代码跑完,结果不正确

3:  异常终止

        我们之前写代码的时候总是先写个main函数,然后return 0,那为什么返回0,返回给谁呢?在linux下是bash创建子进程是帮我们执行代码的,bash这个父进程是需要关心子进程执行的怎么样了,因为bash要向用户报告执行情况,所以需要子进程的退出信息。

        echo $?能获得最近进程的退出码,获得退出码后,lastcode貌似会被更新为0,所以这个时候再来一次echo $呢?,此时获得的是lastcode的初始值0,可能有人会说第二次echo &?获得的lastcode是echo获得的退出码,我认为echo此时没有创建子进程,为什么说echo $?的时候不创建子进程呢?  如果创建了子进程,第一次echo $?会更新lastcode,那退出码不就一直是子进程echo自己的吗,实际上如下:

退出码是1,如果是echo的退出码,那绝对是正常退出的返回码0,不会是1。

        后面我实现shell的时候浅浅想过这个问题,而且我认为echo有时候是会创建子进程的,例如重定向的时候,具体原因不好说,但和重定向有不小的关系,后续再谈。

(2)出错码errno介绍

        因为库函数的返回值并不能说明出错原因,所以想要知道出错码可以看——errno,errno会记录最后一个调用失败的库函数的错误码,但是要转为错误原因,还得用strerror,perror内部也是用了strerror和errno,strerror和perror的区别在于,perror可以给出错文字添加额外的字符串,例如函数名,可以提醒出错位置,可以精准锁定bug。

(3)出现异常,获得的退出码无效?

        有一种解释是说出现异常往往是return之前发生的,没有退出码,所以无效,实际上我去测试让子进程sleep的时候被kill掉,此时还没return,但是退出码却有值,虽然显示的是未知错误,我估计是调用main函数的CRT_START()函数发现main没有退出码,然后外部又要mian的退出码,只能给个随机值了,这个随机值可能就对应一个未知错误。

        此时这个退出码无疑是无意义的,但是还有种情况是我们正常return 了一个未知的退出码,此时进程还没结束(因为main函数结束了,但不代表进程结束了),此时进程被kill了,这个退出码是有用的。

        这两种情况都有异常和退出码,但无法区分这个异常是在返回前出的,还是已经main函数已经return了后出的,感觉也不好区分,所以只能认为退出码无效。简单理解就是你这个进程出了异常,多多少少进程本身都有点错误,所以我们认为执行结果—退出码不能相信。

        如何判断有无异常,看有无信号?(这个下面进程等待会提及)

(4)exit和_exit区别

        _exit是系统调用接口,而exit内部是封装了_exit的,我们来看看它们在结束程序时有什么不同。

test.c ? ?                                                                                                                                                             ?? buffers 
  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 int main()
  6 {
  7    printf("begin\n");
  8    int ret = fork();
  9    if(ret==0)
 10    {
 11         while(1)
 12         {
 13             printf("我是子进程,id:%d",getpid());
 14             exit(0);
 15         }
 16    }
 17    else
 18    {                                                                                                                                                                               
 19        int cnt = 1;
 20        while(cnt)    
 21        { 
 22            printf("我是父进程,id:%d",getpid());
 23            cnt--;
 24            _exit(0);
 25        }
 26    }
 27     return 0;
 28 }
~

        执行结果如下,有个问题就是,父进程打印的数据没了,子进程的却会显示,奇怪这是为什么呢?

        这个就和缓冲区有关了,在windows我们对缓冲区没太多感觉,应该是vs做了特殊封装,让我们几乎感觉不到缓冲区,printf打印其实是往缓冲区打印的,而exit会刷新这个缓冲区,这个缓冲区是用户的,_exit这个系统调用看不见,简单理解缓冲区就是一段malloc的空间,设计者在写系统调用的时候,他怎么会去看你用户malloc的空间要不要刷新呢?

二 什么是进程等待

        是调用系统调用waitpid和wait查看子进程状态和回收子进程资源。

三 为什么要有进程等待

        首先子进程是父进程创建出来帮自己干活的,所以设计者认为需要给父进程提供能获取到子进程退出信息的接口,有很多场景我们都是必须要知道子进程的退出信息的,这个接口是必要的,这就是需要进程等待的原因

        那不能用全局变量吗,不行,因为进程具有独立性父进程看不到子进程的数据,所以拿不到。还有就是子进程退出后会把退出信息存到pcb数据结构中,这个数据结构存在内核数据区,是操作系统内部的数据,是不允许用户访问,简单理解,父进程是我们用户写的代码运行产生的,也就代表用户,所以父进程无法访问子进程的数据,所以必须通过系统调用返回数据。

        而为了让父进程能获取到,会让子进程退出后保持僵尸,不让系统将其处理掉,等待父进程读取状态信息,当父进程获取到子进程退出信息后,就可以销毁子进程了,所以进程等待还附有回收资源的功能。

四 进程等待代码(使用用例)

        目前来看,进程等待是必须的,因为要用于回收子进程资源。那如何进行进程等待,如何使用系统调用呢?

wait介绍

man 3 wait查看man手册中的wait函数介绍。wait参数先不管,等会介绍完waitpid也就知道了

先来看看如何使用。

  1 #include<unistd.h>
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include <sys/types.h>
  5 #include <sys/wait.h>
  6 int main()
  7 {
  8     int id = fork();//创建子进程
  9     if(id < 0)
 10     {
 11         perror("fork error:");
 12     }
 13     else if(id == 0)//子进程
 14     {
 15 
 16         int cnt = 5;
 17         while(cnt--)
 18         {
 19             printf("我是子进程: pid:%d , ppid: %d \n",getpid(),getppid());
 20             sleep(1);
 21         }
 22         exit(0);  退出
 23     }
 24     else
 25     {
 26         int cnt = 10;
 27         while(cnt--)
 28         {
 29             printf("我是父进程: id: %d pid: %d \n ",getpid(),getppid());
 30             sleep(1);
 31         }
 32          //等待子进程
 33         int ret = wait(NULL);                                                                                                                                                      
 34         if(ret == id )//返回正确
 35         {
 36             printf("回收完成\n");
 37         }
 38         else
 39         {
 40             perror("wait\n");
 41         }
 42         sleep(3);
 43     }
 44     return 0;
 45 }

让子进程先退出,父进程一直在printf,此时子进程保持僵尸状态,执行到wait后,回收子进程。

        若是子进程不退呢,父进程将会进入阻塞状态。之前在进程状态描述(scanf场景下)的阻塞状态是在等硬件资源,而现在是在等函数返回值,是在等软件资源,所以说等待资源就会处于阻塞状态。

        wait是等任意一个子进程,那多个子进程会先回收谁,这是不确定的。

waitpaid介绍

        可获得指定子进程的退出信息

参数1:传要回收子进程的pid,如果为-1,表示任意回收一个子进程。

参数2:status参数介绍,首先呢它是可以获取子进程的退出码,若不需要,传NULL即可。


 59           int id = fork();//创建子进程
 60          if(id == 0)
 61          {
 63              exit(1);
 64          }
 69         int status = 0;
 70         int ret = waitpid(-1, &status,0);
 71         printf("回收完成,id : %d 退出码: %d  \n",ret,status);
 73     return 0;
 74 }

        退出码为什么是256呢,子进程不是exit(1)吗,按道理退出码应该是1,这是为什么呢?这就要说status的构成了。0 - 6号比特位上存信号,第7位上是用于core dump,8-15用于退出码,其余位置暂时不关心。

        那如何提取退出码和信号呢?位运算呗。但是这个对程序员的要求有点高,它需要程序员了解status的构成,所以系统提供了一些宏来帮助提取。

printf("退出码: %d,信号: %d\n",WIFEXITED(status),WEXITSTATUS(status));

返回值和等待失败

        当我们等的不是自己的子进程时,这个时候就会等待失败,然后waitpid返回-1,等待成功返回子进程的pid。

参数3 option介绍

        给0选择阻塞等待,就是父进程一直等子进程跑完代码,此时父进程啥也不干。这样有点浪费时间,所以就有了非阻塞轮询,给参数三WNOHANG传,

就是如果子进程没弄好,就直接返回,然后我们外部写个循环,循环调用waitpid,这就是非阻塞轮询时可以做自己的简单代码

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

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

相关文章

Hoppscotch:开源 API 开发工具,快捷实用 | 开源日报 No.77

hoppscotch/hoppscotch Stars: 56.1k License: MIT Hoppscotch 是一个开源的 API 开发生态系统&#xff0c;主要功能包括发送请求和获取实时响应。该项目具有以下核心优势&#xff1a; 轻量级&#xff1a;采用简约的 UI 设计。快速&#xff1a;实时发送请求并获得响应。支持多…

【开源】基于Vue和SpringBoot的网上药店系统

项目编号&#xff1a; S 062 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S062&#xff0c;文末获取源码。} 项目编号&#xff1a;S062&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 药品类型模块2.3 药…

前后端联调时JS数据精度问题的解决

在JavaScript中&#xff0c;Number类型范围 -2^53 1 到 2^53 - 1&#xff0c;而在Java中Long类型的取值范围是 -2^63 1 到 2^63 - 1, 比JavaScript中大很多&#xff0c;所以后端能正常处理。 其实 ES6 引入了 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 这两个常量…

【wvp+ GiVideoCall】 三种主要应用场景

目录 点播场景 聊天室场景 双人视频 点播场景 主动对象&#xff1a; 视频调度平台。 被点播对象&#xff1a; 登录平台的web用户&#xff0c;android用户&#xff1b;国标设备。 功能&#xff1a; 视频点播&#xff1b;伴音&#xff1b;对讲&#xff1b;录相&#xff1b; 聊…

RabbitMQ 安装及配置

前言 当你准备构建一个分布式系统、微服务架构或者需要处理大量异步消息的应用程序时&#xff0c;消息队列就成为了一个不可或缺的组件。而RabbitMQ作为一个功能强大的开源消息代理软件&#xff0c;提供了可靠的消息传递机制和灵活的集成能力&#xff0c;因此备受开发人员和系…

基于Springboot的非物质文化网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的非物质文化网站&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 项目介…

耿明雨出席柬方70周年招待会晚宴

11月9日&#xff0c;庆祝柬埔寨独立和建军70周年欢迎晚宴上&#xff0c;全国政协副主席沈跃跃盛邀出席&#xff0c;此次招待会是由柬埔寨王国驻华大使馆主办&#xff0c;在北京励骏酒店圆满召开&#xff0c;晚宴现场&#xff1b;凯西索达大使致辞、中国外交部部长助理徐飞洪等领…

亓长东、王喜成莅临科大讯飞,共谋科技与服装行业的深度融合

近日&#xff0c;国务院发展研究中心研究员、经济学博士亓长东&#xff0c;雷蒙服饰有限公司董事长王喜成一行莅临科大讯飞进行调研。科大讯飞副总裁张友国热情陪同&#xff0c;双方就科技与服装行业的深度融合进行了深入交流。 在科大讯飞副总裁张友国的陪同下&#xff0c;亓长…

解决Qt5.13.0无MySQL驱动问题

一、前言 由于Qt5.12.3是最后提供mysql数据库插件的版本&#xff0c;往后的版本需要自行编译对应的mysql数据库插件&#xff0c;官方安装包不再提供。使用高版本的Qt就需要自行编译mysql驱动。 若没有编译在QT中调用Qsqldatabase库连接mysql时&#xff0c;提示出现如下问题&a…

Windows系统下使用tar命令,压缩文件与解压缩文件并指定路径

如果想指定解压缩后的文件夹&#xff0c;请看第三步 第一步&#xff1a;进入解压文件所在的当前文件夹内右键点击在终端打开 如下图 第二步&#xff1a;在终端内输入命令行&#xff08;分为两种情况&#xff09; 此步骤分为两种情况 2.1 情况一{文件后缀为.tar.gz} ## x…

VirtualKD-Redux 双机调试内驱驱动

官网使用说明 官网下载地址 简单的说 1. 如果是64位虚拟机&#xff0c;把target64文件夹拷贝到虚拟机中&#xff0c;然后安装vminstall.exe 2. 我电脑是用windbg prview, 在主机上打开 vmmon64.exe 3 设置DbgX.Shell.exe路径 D:\安装\WinDbg Preview1.1910.3003.0\Microsoft…

C++进阶-STL 常用算法列举

STL 常用算法列举 概述常用遍历算法for_each 遍历容器transfrom 搬运容器到另一个容器中 常用查找函数find 查找元素find_if 按条件查找元素adjacent_find 查找相邻重复元素binary_search 二分查找法count 统计元素个数count_if 按条件统计元素个数 常用排序算法sort 对元素内内…

Java获取Jar、War包路径,并生成可编辑修改的本地配置文件

前言 本地的可修改配置文件的编写理应是一个很常用的功能&#xff0c;但由于数据库的存在&#xff0c;它鲜少被提及&#xff0c;大多数我们直接存储到数据库中了。 以至于现今&#xff0c;除了没接触数据库的新手时常使用它以外&#xff0c;它没有太多的出场机会。 也因此&am…

第九章认识Express模板

基本概述 Express模板是指Express框架中用于渲染视图的文件&#xff0c;可以包含HTML、CSS、JavaScript等内容&#xff0c;用于构建Web应用程序的用户界面。 使用Express模板可以快速、方便地创建Web应用程序&#xff0c;并且可以轻松地将动态数据注入到模板中&#xff0c;以…

印染污水处理设备有哪些分类

印染污水处理设备有多种分类方法。根据处理方法&#xff0c;可以分为物理法、化学法、生物法等。 物理法处理设备主要包括格栅、沉淀池、过滤器等&#xff0c;利用物理分离、去除的原理&#xff0c;将污水中的悬浮物和沉淀物去除。化学法处理设备主要包括混凝和氧化等&#xf…

Abaqus 2023有哪些新功能?

Fe-safe/Isight/Tosca2022新功能 近日&#xff0c;达索3ds官网发布了Abaqus 2023的最新消息&#xff0c;在接下来的数周内&#xff0c;SIMULIA套件GA版将正式与大家见面。 据悉&#xff0c;Abaqus 2023整合了该级别的最新功能和上一个级别的前四个补丁版的新增/增强功能&#…

安防监控展示预约小程序的作用如何

监控在生活中的用途非常广泛&#xff0c;普遍应用于小区门户、商业大厦、产业基地、家庭、汽车等场景中&#xff0c;市场需求较大&#xff0c;同时随着科技发展&#xff0c;安防监控产品更新迭代也比较快&#xff0c;衍生出的经销店、安装技术工等产业近些年也比较火。 安防监…

Elasticsearch搜索分析引擎本地部署与远程访问

文章目录 系统环境1. Windows 安装Elasticsearch2. 本地访问Elasticsearch3. Windows 安装 Cpolar4. 创建Elasticsearch公网访问地址5. 远程访问Elasticsearch6. 设置固定二级子域名 Elasticsearch是一个基于Lucene库的分布式搜索和分析引擎&#xff0c;它提供了一个分布式、多…

中移链共识机制介绍

01 为什么需要共识 共识是对某事达成的共同看法&#xff0c;它是区块链的灵魂&#xff0c;对确保区块链的完整性和安全性起着至关重要的作用。在传统的集中式系统中&#xff0c;单个实体或一组实体有权验证和记录交易。然而&#xff0c;区块链中的一个核心概念是去中心化&…

LeetCode - 160. 相交链表(C语言,配图)

思路&#xff1a; 1. 我们算出两个链表的长度lenA&#xff0c;lenB。我们在这里最后判断一下&#xff0c;两个链表的尾节点是否是一样的&#xff0c;如果是相交链表&#xff0c;那它们的尾节点一定是一样的。 2. 算出长链表和短链表的差距n&#xff08;n | lenA- lenB |&#…