【Linux】进程控制(创建、终止、等待)

环境:centos7.6,腾讯云服务器
Linux文章都放在了专栏:【Linux】欢迎支持订阅

相关文章推荐:

【Linux】冯.诺依曼体系结构与操作系统

【Linux】进程理解与学习Ⅰ-进程概念

【Linux】进程理解与学习Ⅱ-进程状态

【Linux】进程理解与学习Ⅲ-环境变量

【Linux】进程理解与学习Ⅳ-进程地址空间

浅谈Linux下的shell--BASH

【Linux】进程优先级&前后台理解

前言

在前文中我们了解了fork函数的使用,以及写时拷贝机制的原理等,并且也学习了什么是僵尸进程,但是并没有具体讲到应如何处理僵尸进程,本次章节将对fork函数以及如何终止进程,还有僵尸进程的处理做更为详细的探讨。

进程创建

  • 再谈fork函数

#include <unistd.h>
pid_t fork(void);
返回值:创建子进程成功后,给子进程返回0,父进程返回子进程的pid,出错返回-1
pid_t 实际上就是int 的typedef

在调用fork函数的时候,会分配新的内存块和内核数据结构给子进程,并将父进程的部分数据结构内容拷贝给子进程(包括环境变量表)。

 当调用fork函数之前,父进程独立运行,调用fork之后,会执行两个执行流,即父子进程共享fork函数之后的代码。

  • 写时拷贝

写时拷贝可以说是一种“赌博式”的机制,在前文【进程地址空间】一文中已经具体的进行讲解。所谓写时拷贝实际上就是当一方进程想要对数据进行修改时,OS会在物理内存中重新开辟一块空间,并将原有物理空间的内容进行拷贝,最后将新空间的物理地址通过页表+MMU与原有虚拟地址重新建立映射关系。(给用户呈现的就是同一个地址却有两个不同的值)

 进程终止

  • 退出码

每一个进程在退出时都会有一个退出码,就好像我们写main函数时最后加上return 0,这就表示退出码为0。我们在Linux下可以通过echo $?指令查看最近的进程的退出码

而对于各个退出码表示的含义,我们可以利用函数strerror,通过以下代码打印出来: 

#include<stdio.h>
#include<string.h>
 
//退出码
int main()
{
  int n=255;
  for(int i=0; i<n; ++i)
  {
    //strerror:将数字退出码转化为对应的字符串类型
    printf("%d:%s\n",i,strerror(i));                                                                                                         
  }
  return 0;                
}     
部分退出码含义(C语言标准)

还有一点需要注意的是,进程的退出码的数值范围一般都在0~255之内,假如超出了这个范围,则会返回退出码255。

  •  退出方式

对于一个进程,我们除了可以通过外部指令(比如kill -9 pid或者ctrl c等)来终止进程,还可以通过内部实现的函数,来终止一个进程。常见的三个函数如下:

1、main函数中的return语句

该方法是最为常见的一种方法,当在main函数中执行return指令,则表示该进程终止,并返回return后面的退出码。不过这里需要注意的是,只有main函数中的return才表示进程终止。

 2、exit函数

除了main函数中的return语句可以用来终止进程,实际上还可以通过函数exit用来终止该进程。exit与return的不同之处就在于,调用了exit之后,不管在哪个函数体(无论是普通函数,还是main函数)都会终止进程

3、 _exit函数

_exit与exit看起来长得好像,那么它的作用是什么呢?与exit有什么区别吗?

实际上两者的共同点就是,两者都是当执行到该语句时,就会终止进程,唯一的区别就在于exit在终止进程之前会刷新缓冲区,而_exit则是直接结束进程。如下:

实际上,_exit是一个系统调用函数,需要 包含头文件<unistd.h>。而exit可以说是_exit的封装,如下:

  •  退出结果

对于一个进程的退出结果,无非就以下三种情况:

  • 程序正常退出,且执行结果正确
  • 程序正常退出,且执行结果错误
  • 程序异常

进程退出的进一步理解:OS在进程退出时,会释放该进程对应的内核数据结构+代码和数据(因此,僵尸进程问题的解决是必要的,否责会一直存在,占用系统空间资源,造成内存泄露)

进程等待

  • 进程等待的原因

在前文进程状态中讲到了,子进程是要让父进程拿到自己的退出码以及退出状态,否则就算自己被kill掉了,也是处于一种僵尸状态(Z状态)存在着,直到父进程拿到自己的退出码以及退出状态,子进程才结束僵尸状态(bash的子进程由于bash有回收机制,所以不会出现僵尸进程)。

僵尸进程(Z)

对于父进程来说,子进程的执行结果是否正确并不重要,重要的是子进程的退出状态,即子进程是否是正常退出。而子进程的执行结果是否正确则是由程序员根据退出码自行判断。(注意:判断退出码是否正确的前提是进程是否正常退出

对于僵尸进程问题的解决,父进程是通过进程等待的方式,回收子进程资源,获取子进程退出信息,从而解决僵尸进程问题。

总而言之,进程等待的目的只有两个,如下:

  1. 解决僵尸进程问题,避免内存泄漏(必须要做的)
  2. 获取子进程的退出结果(如果需要的话)
  • 进程等待的方法

那么父进程应如何等待呢?实际上系统提供了函数,wait与waitpid函数。

wait函数

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

 wait函数的使用很简单,接下来着重介绍waitpid函数的使用,该函数是我们比较常用的一个函数,用法相较于wait也稍微复杂了一些。

waitpid函数 

为了更好更直观的认识该函数,我画了如下图解:

当然,仅仅只有图是不够的,接下来通过如下代码来演示进程等待的阻塞与非阻塞等待。

阻塞式等待

将waitpid的第三个参数设置为0,就表示阻塞式等待。所谓阻塞式等待,就是父进程运行到waitpid该处的指令时,不会再往后继续执行指令,而是处于阻塞状态等到子进程退出时,才会继续执行后面的指令

 #include<stdio.h>
 #include<unistd.h>
 #include<sys/types.h>
 #include<sys/wait.h>
 #include<stdlib.h>

 int main()
{
   pid_t id=fork();
   if(id == 0)
   {
     //child
     int cnt=5;
     //子进程五秒后会退出
     while(cnt)
     {
       printf("我是子进程,还有%ds退出,pid:%d\n",cnt,getpid());
       --cnt;
       sleep(1);
     }
     if(cnt == 0)exit(111);
     else exit(-1);
   }
   //父进程等待子进程退出(阻塞式等待)
   printf("我开始等待子进程退出\n");
   int status=0;
   pid_t w=waitpid(id,&status,0);//0表示阻塞式等待,只有子进程结束时,父进程才会执行后面的指令                                                  
   //等待失败
   if(w<0)
   {
      perror("wait fail");
     return -1;
   }
   //等待成功
   printf("我是父进程,等待子进程成功,w:%d,子进程退出码:%d,退出信号:%d\n",w,(status>>8)&0xFF,status&0x7F);
   //status >> 8后得到低16位的高8位,& 0xFF则取到该8位对应的值,%d以十进制打印(退出码)
   //status &0x7F则是取到低7位的值,并以10进制打印(退出信号)
 }

先来看一下执行结果:

​ 当然,我们不仅可以通过位运算获得子进程的退出码以及退出信号,也可以通过系统提供的宏来获取:

  1. WIFEXITED(status)若子进程退出信号正常,则返回真,异常返回假(通常用0表示假,非0表示真)
  2. WEXITSTATUS(status)查看退出码(用户自己根据退出码来判断是否执行结果正确,前提是退出信号正常)

非阻塞式等待

将waitpid的第三个参数设置为WNOHANG,就表示非阻塞式等待。所谓非阻塞式等待,就是父进程在执行waitpid指令时,假如子进程没有退出,则会给waitpid返回一个0,然后继续执行后面的指令。我们可以通过等待轮询的方式,来保证在等待子进程的同时,父进程得以做一些其他的事。如下:

 #include<stdio.h>
 #include<unistd.h>
 #include<sys/types.h>
 #include<sys/wait.h>
 #include<stdlib.h>
 
 //非阻塞式等待
 int main()
 {
   pid_t id=fork();
   if(id == 0)
   {
     //child
     int cnt=3;
     //让子进程3秒后退出
     while(cnt)
     {
       printf("我是子进程,还有%ds退出,pid:%d\n",cnt,getpid());
       --cnt;
       sleep(1);
     }
     if(cnt == 0)exit(111);
     else exit(-1);
   }

   //father               
   //等待轮询
   while(1)
   {
     int status=0;        
     //第三个参数设置为WNOHANG,表示非阻塞式等待,父进程可以执行后面的指令                                                                     
     pid_t tmp=waitpid(id,&status,WNOHANG);
     //等待失败
     if(tmp < 0)
     {
       perror("wait fail\n");
       exit(-1);
     }
     //子进程还未退出
     else if(tmp == 0)
     {
       printf("子进程还未退出,我可以做其它的任务\n");
       printf("执行任务-------\n");
       sleep(1);
     }
     //子进程退出
     else 
     {
       printf("子进程已退出,父进程接受子进程返回信息,子进程退出码:%d,退出信号:%d\n",WEXITSTATUS(status),status&0x7F);
       break;
     }
   }
   return 0;
 }


end.

生活原本沉闷,但跑起来就会有风!🌹 

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

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

相关文章

网络编程socket(下)

目录 一、TCP网络程序 1.1 服务端初始化 1.1.1 创建套接字 1.1.2 服务端绑定 1.1.3 服务端监听 1.2 服务端启动 1.2.1 服务端获取连接 1.2.2 服务端处理请求 1.3 客户端初始化 1.4 客户端启动 1.4.1 发起连接 1.4.2 发起请求 1.5 网络测试 1.6 单执行流服务端的…

非科班应届生培训Java能就业吗?

想要学习Java开发的同学们&#xff0c;不要再太过纠结非科班可以学Java吗&#xff1f;学历低能学Java开发吗?Java开发怎么才能学得好?没有计算机基础能学习Java开发吗&#xff1f;这些问题了。想的再多都不如行动&#xff0c;大胆努力认真踏实地学习就好。谁不是一步步来的呢…

GPT-4老板:AI可能会杀死人类,已经出现我们无法解释的推理能力

来源: 量子位 微信号&#xff1a;QbitAI “AI确实可能杀死人类。” 这话并非危言耸听&#xff0c;而是OpenAI CEO奥特曼的最新观点。 而这番观点&#xff0c;是奥特曼在与MIT研究科学家Lex Fridman长达2小时的对话中透露。 不仅如此&#xff0c;奥特曼谈及了近期围绕ChatGPT…

如何同时处理多个聊天

作为跨境电商企业&#xff0c;有没有想过您的客服成员同时处理多个聊天有多大挑战&#xff1f;如果他们在管理多个聊天时犯了错误&#xff0c;或者他们的一个响应提示访问者在获得解决方案之前离开网站怎么办&#xff1f; 是的&#xff0c;毫无疑问&#xff0c;最好的实时支持聊…

微服务_微服务的架构演进之路

目录 一、前言 二、单体架构 三、分布式架构 四、微服务 五、SpringCloud 六、服务拆分 5.1服务拆分原则 5.2服务拆分示例 一、前言 微服务是一种软件开发架构风格&#xff0c;它将单个应用程序拆分成多个小型服务&#xff0c;每个服务都具有自己的特定功能。这些服务…

【开发实践】在线考试系统(三) Sortable实现试题的重排序

一、需求分析 开发一个在线考试系统&#xff0c;在教师组卷功能模块中&#xff0c;需要对已经选择的试题进行重排序&#xff0c;获得所需试题顺序的试卷。 如下是试卷编辑页面&#xff0c;需要在将已经选中的试题重排顺序。 二、技术引入 1、sortable.js sortable.js 官方…

太敢说了,编程如果这么自学,培训班都得倒闭,直接省去上万元的学费

写了20多年的代码&#xff0c;之前做过阿里的高级架构师&#xff0c;在技术这条路上跌跌撞撞了很多&#xff0c;我今天分享一些我个人的自学方法给各位。现在在网上报个正经点的班得花几千块钱&#xff0c;线下就更夸张&#xff0c;都是万元起步,我的这些学习方法如果你能用好&…

【iOS】—— 多线程之pthread、NSThread

文章目录1.pthreadpthread简介&#xff1a;pthread使用方法pthread 其他相关方法2.NSThread创建&#xff0c;启动线程线程相关用法线程相关用法线程状态控制方法线程之间的通信NSThread线程安全和线程同步NSThread 非线程安全NSThread 线程安全线程的状态转换NSThread线程属性n…

GPT-4问世;LLM训练指南;纯浏览器跑Stable Diffusion

1.多模态GPT-4正式发布&#xff1a;支持图像和文本输入&#xff0c;效果超越ChatGPT OpenAI的里程碑之作GPT-4终于发布&#xff0c;这是一个多模态大模型&#xff08;接受图像和文本输入&#xff0c;生成文本&#xff09;。主要能力有&#xff1a; GPT-4可以更准确地解决难题&a…

基于SpringBoot的校园疫情防控系统设计与实现

1.概述 校园疫情防控系统的开发运用java技术、springboot框架&#xff0c;MIS的总体思想&#xff0c;以及Mysql等技术的支持下共同完成了该系统的开发&#xff0c;实现了校园疫情防控管理的信息化&#xff0c;使用户体验到校园疫情防控管理&#xff0c;管理员管理操作将更加方…

2023.04.02 学习周报

文章目录摘要文献阅读1.题目2.摘要3.简介4.本文贡献5.PROBLEM FORMULATION5.1 Case Study5.2 Problem Definition6.MODEL6.1 Absolute Temporal Module6.2 Relative Temporal Module6.3 Decoder Module6.4 Loss Function7.实验7.1 数据集7.2 评价指标7.3 基线7.4 实验结果8.结论…

R语言数据处理学习记录--用自己的数据完成mental test(使用ggcor包)

R语言数据处理学习记录–用自己的数据完成mental test&#xff08;使用ggcor包&#xff09; 注&#xff1a;本文仅作为自己的学习记录以备复习查阅 关于科学上网&#xff1a;https://www.zhihu.com/question/498939985 一 ggcor包的简介及其安装 ggcor的目标是提供一组可以…

【Nvidia】nvidia 高级特性MIG详细介绍(二)

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

seaborn从入门到精通03-绘图功能实现03-分布绘图distributional plots

seaborn从入门到精通03-绘图功能实现03-分布绘图distributional plots总结参考关系-分布-分类分布绘图-Visualizing distributions data图形级接口displot/jointplot/pairplot--figure-level interface轴级接口histplot/kdeplot/ecdfplot/rugplot--axes-level interface导入库与…

C++/MFC工程[4]——绘制直线段

一、MoveTo()函数和LineTo()函数 本文实例均于 ***View().cpp文件中的OnDraw()函数中实现。 两函数在上上节C/MFC工程[2]——自定义平面直角坐标系中已经有所应用。 MoveTo()函数只设置起点&#xff0c;不画线。 LineTo()函数进行画线&#xff0c;画线结束后&#xff0c;起点变…

php微信小程序java+Vue高校课程课后辅导在线教育系统nodejs+python

目 录 1绪论 1 1.1项目研究的背景 1 1.2开发意义 1 1.3项目研究现状及内容 5 1.4论文结构 5 2开发技术介绍 7 2.1 B/S架构 7 2.2 MySQL 介绍 7 2.3 MySQL环境配置 7 2.5微信小程序技术 8 3系统分析 9 3.1可行性分析 9 3.1.1技术可行性 9 3.1.2经济可行性 9 3.1.3操作可行性 10 …

软考-软件测试

一.测试概述经典定义在规定的条件下对程序进行操作&#xff0c;已发现错误&#xff0c;对软件质量进行评估对象程序&#xff0c;文档&#xff0c;数据目的发现软件的错误&#xff0c;验证软件是否满足用户需求&#xff0c;并通过分析软件错误产生原因&#xff0c;以帮助开发工作…

蓝桥杯C/C++VIP试题每日一练之完美的代价

💛作者主页:静Yu 🧡简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者 💛社区地址:前端知识交流社区 🧡博主的个人博客:静Yu的个人博客 🧡博主的个人笔记本:前端面试题 个人笔记本只记录前端领域的面试题目,项目总结,面试技…

别把 OpenAI 太当回事,它远未达到替换前端的地步

最近几个月&#xff0c;我和很多初入行的开发人员交谈&#xff0c;他们对AI越来越感到焦虑。他们看到像GPT-4这样的工具展示的越来越令人印象深刻的演示&#xff0c;担心等他们掌握了HTML/CSS/JS&#xff0c;就没有任何工作机会了。这种情绪现在在Twitter上广泛存在&#xff1a…

锐捷AP虚拟化配置

本次使用AC型号为WS6008 &#xff0c; 版本AC RGOS 11.9(6)W2B1 Release(10142114) 使用的AP型号为AP720-I &#xff0c;版本为AP RGOS 11.1(9)B1P30, Release(08190211) 升级主要参考指南闪电兔Pro 组网拓扑&#xff1a; 主要配置&#xff1a; 当前状态是AC已经能够管理AP …
最新文章