【Linux的进程篇章 - 进程终止和进程等待的理解】

Linux学习笔记---008

  • Linux之fork函数、进程终止和等待的理解
    • 1、fork函数
      • 1.1、什么是fork?
      • 1.2、fork的功能介绍
      • 1.3、fork函数返回值的理解
      • 1.4、fork函数的总结
    • 2、进程的终止
      • 2.1、终止是在做什么?
      • 2.2、进程终止的3种情况
    • 3、进程的终止
      • 3.1、进程终止的三种情况
      • 3.2、判断是否成功的顺序
      • 3.3、如何终止
    • 4、进程等待
      • 4.1、直接先看结论
      • 4.2、进程等待怎么处理呢?

Linux之fork函数、进程终止和等待的理解

前言:
前篇开始进行了解学习Linux的进程优先级、环境变量、地址空间等知识,这篇学习LInux的fork函数、进程终止和等待的理解等相关内容,深入地了解这个强大的开源操作系统。
/知识点汇总/

1、fork函数

前言:

进程:内核的相关管理数据结构(task_struct + mm_struct(内存分配表) + 页表) + 代码和数据

1.1、什么是fork?

直接man fork指令先在手册页查看以下基本信息:
在这里插入图片描述
补充:
在这里插入图片描述

man fork提示no manual entry for fork,则说明你当前没有安装man手册.

解决方法就是

root权限下:yum -y install man-pages

基本概念

fork() 是 Unix/Linux系统中的一个非常重要的系统调用,用于创建一个新的进程,这个新的进程是当前进程的复制品,称为子进程。这个复制过程包括父进程的代码、数据、堆、栈等内容都会被复制到子进程中。

1.2、fork的功能介绍

头文件:
#include <unistd.h>
原型:
pid_t fork(void)
返回值:
-1 ---- fork创建/调用子进程失败
==0 — 返回0是判断创建子进程成功
!=0 — 返回非负整数,表示返回新创建的子进程的进程ID,即,父进程返回的子进程pid

测试代码
在这里插入图片描述
fork语句之后的程序,父子进程共享代码 —> fork创建一个进程,本质是系统中多一个进程;
而多一个进程,也就是多一个进程控制块(task_struct)
父进程的代码和数据是从磁盘加载来的;子进程的代码数据是哪里来的呢?
子进程会默认继承父进程的代码和数据。

我们为什么要创建一个子进程呢?
通常来说,是想要子进程执行和父进程不一样的代码,常规的程序都是单进程,不可能同时跑不同的代码内容。多进程情况下,则是合理的。

对于普通的单进程程序,只能有一个返回值;
对于多进程,那么为什么同一个程序同一个id,会有两个值,即是0又是!=0?
其次,fork怎么会有两个返回值,即返回两次呢?怎么做到的呢?
(涉及虚拟地址空间和父子写时拷贝知识,见这篇文章)

1.3、fork函数返回值的理解

fork也是一个函数,只不过属于系统调用。
然后平常的普通程序中的return在fork执行语句之后,即当执行完fork后,父子代码数据共享,
子进程代码中自然也有了return语句,所以父子进程各自被调度一次,那么自然就返回两次且值可以不同

引出一个概念:理论上,子进程被创建后是空的,自然其代码和数据就从父进程哪里拷贝获取,
就比如有window的任务管理器,有两个子进程由一个父进程创建,当此时关系结束一个子进程会影响其它进程?
当然不会的,逻辑上是父子等关系,实际上是分裂独立的。

所以进程一定要具备的特点就是

具备独立性,即一个进程出现问题,绝不能影响其它进程。

进程 = 内核task_struct结构体(唯一的pid) + 代码程序(只读/共享的)和数据(父子数据各自独立,原则上数据需要分开)每一个进程都有一个自己唯一的标识符,叫做进程pid

fork()函数返回值:

1.子进程返回0
2.父进程返回子进程pid

为什么父进程返回的是子进程的pid,而子进程返回的是0?
因为父进程返回子进程的pid是对它更好的进程管理,而子进程返回值是判断创建子进程是否创建成功。
即:为了父进程对子进程进行标识,方便管理。

fork的常规用法:

1.一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
2.一个进程要执行一个不同的程序。例如子进程从fork()返回后,调用exec函数

fork()调用失败的原因:

1.系统中已有太多的进程。
2.实际用户的进程数超过了限制。

1.4、fork函数的总结

总结:

1.fork()函数在Linux中用于创建一个新的进程,这个新进程是当前进程的复制品,称为子进程。
2.fork()函数的特点在于它只被调用一次,但却能返回两次:一次在父进程中,一次在子进程中。

关于fork()函数的返回值,具体总结如下:

1.在父进程中,fork()函数返回新创建的子进程的进程ID(PID)。
2.这个PID是一个非负整数,用于唯一标识子进程。
3.在子进程中,fork()函数返回0。这是因为在子进程的上下文中,它自己是新创建的进程,所以没有其他的进程ID可以返回。返回0表示子进程成功创建。
4.如果fork()函数执行过程中发生错误,例如由于系统资源不足而无法创建新的进程,那么它会返回一个负值。这个负值通常表示特定的错误码,可以通过检查这个值来确定具体的错误原因。
5.需要注意的是,fork()函数创建的子进程是父进程的副本,包括父进程的代码、数据、堆、栈等内容都会被复制到子进程中。但是,这两个进程有不同的进程ID,并且它们从fork()函数的返回点开始独立执行。
6.因此,通过检查fork()函数的返回值,可以在父进程和子进程中执行不同的代码路径,从而实现并发执行或创建多进程程序。

2、进程的终止

2.1、终止是在做什么?

释放曾经的代码和数据所占据的空间;理解为释放内核的数据结构 ,否则–>僵尸态

2.2、进程终止的3种情况

测试代码
在这里插入图片描述

echo $?
内建命令,打印的都是bash本身内部的变量数据。通常0:成功 非0:标识失败
其中?属于bash维护的一个变量
表示的是,父进程bash获取到的,最近的一个子进程退出的退出码
目的:
告诉父进程(关心结果),我把任务完成得怎么样
0:标识成功
非0:标识失败
非0的数值。一方面可表示失败,另一方面可表示失败的原因。即都有相应的错误描述。

测试代码
在这里插入图片描述
在这里插入图片描述

父进程为什么要得到子进程的退出码呢?
答:要知道子进程的退出情况(成功、失败以及失败的原因),本质退出的情况信息,告诉给用户的。

退出码可以使用默认的,同时也可以自定义。
测试代码
在这里插入图片描述

3、进程的终止

3.1、进程终止的三种情况

a、代码跑完,进程正确;
b、代码跑完,进程不正确。

可以通过进程的退出码决定。反馈原因:系统的 && 自定义退出码

c、代码异常终止,提前退出

操作系统发现了你的进程做了不该做的事情,就会被OS自主杀掉该进程。而且一旦出现异常,退出码就没有意义了。

需要关心的是为什么会出异常呢?

1.进程出异常,本质上是由操作系统(OS)向进程发生了一个信号。
2.我们可以查看进程退出的时候,退出的信号是多少,就可以判断,我的进程为什么异常了。
常见情况有:
a、段错误
b、栈溢出

3.2、判断是否成功的顺序

1.先确认是否是异常。
2.不是异常,就一定是代码跑完了。看退出码是否符合预期就行。

结论

衡量一个进程退出,我们只需要两个数字(反馈给父进程):退出码和退出信号(2^2)。
task_struct()会包含一些字段信息。用于匹配反馈。
比如:exit_code和exit_signal
0 0
0 !0
!0 0
!0 !0
由退出码+退出信号 --》退出进程退出的原因。

3.3、如何终止

a、main()函数return 表示进程终止(非main函数,return,函数结束)
b、代码调用exit()函数,可在代码的任意位置退出,并冲刷缓冲区。
void exit(int status);
c、_exit()–系统调用,与exit的区别不会冲刷缓冲区。
void _exit(int status);
注意:这里所说的缓冲区,不是内核的缓冲区。

4、进程等待

4.1、直接先看结论

任何子进程,在退出的情况下,一般必须都要有父进程进行等待,进程在退出的时候,如果父进程不管不顾(不等待),直到退出进程,导致状态Z(僵尸状态),造成内存泄漏的问题。

为什么?

1.通过父进程等待,解决子进程退出的僵尸问题,回收系统资源(一定要注意)
2.获取子进程的退出信息,知道子进程是因为什么原因退出的(前提是如果需要的话,不是必须的)

4.2、进程等待怎么处理呢?

答:通过两个函数wait()函数和waitpid函数

阻塞等待测试代码
在这里插入图片描述

查看指令

while :; do ps ajx | head -1 && ps ajx | grep wait_process | grep -v
grep;sleep 1;done

说明

头文件:
#include <sys/types.h>
#include <sys/wait.h>
函数原型:
pid_t wait(int* status);
返回值:
pid_t:等待成功时,子进程的pid给返回
参数:
status:等待父进程中,任意一个子进程的退出
功能:
用于解决子进程僵尸进程的。(defunct僵尸态)

如何理解阻塞等待子进程呢?
如果子进程没有退出,父进程就会一直处于进行阻塞等待的状态(死等)
子进程本身就是软件,父进程本身就是等待某种软件的条件就绪。

头文件:
#include <sys/types.h>
#include <sys/wait.h>
函数原型
pid_t waitpid(pid_t pid,int* status,int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程id;
如果设置了选项,而调用waitpid发现没有已退出的子进程收集,则返回0;
如果调用中出错,则返回error会被设置成相应的值以指示错误所在。
1.正常返回时,返回的收集到的子进程id;
2.如果设置了option选项参数为WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
3.如果调用失败,则返回-1,且errno会被设置为相应的值得以指示错误所在。
参数:
pid=-1:等待任意个子进程的pid,与wait相同;
pid>0:等待其进程id与pid相等的子进程;

参数二说明

status具有特定的格式。(低16位)
1.输出型参数,表示的是输出信息
高八位 – 退出状态
低八位 – 终止信号
2.参数二:status
WIFEXITED(status):若为正常终止子进程的状态,则返回真 — 作用是查看进程是否正常退出
WEXITSTATUS(status):若WIFEXITED非零,提取子进程退出码 ---- 查看进程的退出码
WNOHANG:若pid指定的子进程没有进程,则waitpid()函数返回0,不予以等待,若正常结束,则返回该子进程的ID。

非阻塞等待测试代码
在这里插入图片描述

如果子进程没有退出,而父进程在进行执行waitpid进行等待,阻塞等待(scanf()…的原理)。
所以阻塞就是进程阻塞。
直到等待某种条件的发生(比如子进程的退出)
那么一些非阻塞等待,属于服务器宕机。
阻塞等待和非阻塞的等待本质区别就是判断是否有返回值,是否达成某成条件。

即:pid_t > 0:等待是成功的,子进程退出了,并且父进程回收成功;
pid_t < 0:等待失败了;
pid_t == 0:检测是成功的,只不过子进程还没有退出,需要你下一次进行重复等待。

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

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

相关文章

深度学习简介

深度学习简介 一、引言&#xff1a;深度学习的兴起 简短介绍深度学习的历史背景 深度学习&#xff0c;作为人工智能领域的一颗冉冉升起的新星&#xff0c;其根源可以追溯到上世纪的感知机学习算法。这种算法模拟人类的神经元行为&#xff0c;是最早期的尝试之一。然而&#x…

一天300收入打底,​一个适合任何人的创业项目!

共享旅游卡项目&#xff0c;一天300收入打底&#xff0c;一个适合任何人的创业项目&#xff01; 只要你不懒&#xff0c;生活总过得不会太差。只要你不贪&#xff0c;就算不能大富大贵&#xff0c;至少不会负债累累。 人性最难戒掉的两个字&#xff1a;一个是懒&#xff0c;另…

Web安全漏洞原理(5万字最全总结)

资料来源–安恒攻防实验室 目录 SQL注入漏洞 漏洞原理 举例说明 测试方式 数字型注入&#xff1a;字符型注入&#xff1a;搜索型注入&#xff1a; 判断注入方式如何利用漏洞 识别数据库类型注入方法&#xff08;union&#xff09; 绕过过滤方式 大小写混合替换关键字使用编码…

Java——数组练习

目录 一.数组转字符串 二.数组拷贝 三.求数组中元素的平均值 四.查找数组中指定元素(顺序查找) 五.查找数组中指定元素(二分查找) 六.数组排序(冒泡排序) 七.数组逆序 一.数组转字符串 代码示例&#xff1a; import java.util.Arrays int[] arr {1,2,3,4,5,6}; String…

Python(1):认识Python并且了解一些简单函数

文章目录 一、Python的优势及其使用场景二、Python环境的安装三、Python中的变量及其命名四、Python中的注释五、一些简单常见的函数和认识ASCII表六、Python导入模块的方式 一、Python的优势及其使用场景 优点&#xff1a; 开发效率高&#xff1a;Python具有非常强大的第三方…

工业智能终端助力工业自动化的关键

在当今数字化时代&#xff0c;工业自动化已经成为工业生产中的重要趋势。随着工业互联网的发展&#xff0c;工业智能终端作为关键技术之一&#xff0c;正在为工业自动化的实现提供了重要支持和保障。 一、工业平板电脑 工业平板电脑具备显示与交互功能&#xff0c;可满足数采、…

rust使用print控制台打印输出五颜六色的彩色红色字体

想要在控制台打印输出彩色的字体&#xff0c;可以使用一些已经封装好的依赖库&#xff0c;比如ansi_term这个依赖库&#xff0c;官方依赖库地址&#xff1a;https://crates.io/crates/ansi_term 安装依赖&#xff1a; cargo add ansi_term 或者在Cargo.toml文件中加入&#…

Meta宣布全新训推一体加速器:完全集成PyTorch 2,性能3倍提升

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 Meta 疯狂砸入数十亿美元&#xff0c;一部分招揽人才&#xff0c;一部分造芯片。 Meta 正在不…

PyQt5+Pycharm, QThread

一、创建窗体控件 untitled.ui&#xff1a; PushButton, PushButton_2, PushButton_3 lineEdit, lineEdit_2, lineEdit_3 二、编译窗体 自动生成untitled.py 三、新建py文件 myDemo.py import sys from PyQt5.QtWidgets import QApplication, QMainWindow from untitled…

第四百五十三回

文章目录 1. 问题描述2. 优化方法2.1 缩小范围2.2 替代方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取AppBar的高度"相关的内容&#xff0c;本章回中将介绍关于MediaQuery的优化.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 问题描述 我们在…

【学习】移动端兼容性测试有什么方法及重要性

随着移动互联网的快速发展&#xff0c;移动应用程序已经成为人们日常生活中不可或缺的一部分。然而&#xff0c;由于各种移动设备的硬件和软件差异&#xff0c;移动应用程序的兼容性问题也越来越突出。因此&#xff0c;移动端兼容性测试成为了一个重要的环节&#xff0c;它可以…

超越ChatGPT,国内快速访问的强大 AI 工具 Claude

claude 3 opus面世后&#xff0c;网上盛传吊打了GPT-4。网上这几天也已经有了许多应用&#xff0c;但竟然还有很多小伙伴不知道国内怎么用gpt&#xff0c;也不知道怎么去用这个据说已经吊打了gpt-4的claude3。 今天我们想要进行的一项尝试就是—— 用claude3和gpt4&#xff0c…

Flyway Desktop 连接使用教程

&#xff01;&#xff01;&#xff01;这是到新的项目组&#xff0c;别人都配置好了&#xff0c;我只是用工具连接的教程&#xff0c;具体怎么和项目配置&#xff0c;请自行查阅。 1.下载软件 官网地址Home - Product Documentation 2.New project 3.创建Flyway工作路径 4.添…

CorelDRAW21.2.4中文最新官方和谐版下载

CorelDRAW是一款由加拿大Corel公司出品的平面设计软件&#xff0c;也被称为CDR。它是一款功能强大的矢量图形制作和排版软件&#xff0c;主要面向绘图设计师和印刷输出人员。该软件提供了矢量插图、页面布局、图片编辑和设计工具&#xff0c;广泛应用于排版印刷、矢量图形编辑及…

DELL VMWare R730 R740 R750 iDRAC配置与ESXI安装部署

VMware vCenter Server与ESXI版本兼容对照表 ESXI下载 VMware vcenter7.0许可证 Esxi7.0许可证 VSAN 7.0许可证 DELL VMWare R730 R740 R750 iDRAC配置与ESXI安装部署 vmware vcenter server 7.0 安装教程 1. 进入BIOS界面配置iDRAC网络 开机按F10&#xff0c;开机点击F10选择…

java八股——消息队列MQ

上一篇传送门&#xff1a;点我 目前只学习了RabbitMQ&#xff0c;后续学习了其他MQ后会继续补充。 MQ有了解过吗&#xff1f;说说什么是MQ&#xff1f; MQ是Message Queue的缩写&#xff0c;也就是消息队列的意思。它是一种应用程序对应用程序的通信方法&#xff0c;使得应用…

AI大模型专题:2024大模型赋能下的AI 2.0数字人平台白皮书

今天分享的是AI大模型专题系列深度研究报告&#xff1a;《AI大模型专题&#xff1a;2024大模型赋能下的AI 2.0数字人平台白皮书》。 &#xff08;报告出品方&#xff1a;商汤&#xff09; 关键发现 生成式 AI 和大模型技术的飞速发展正推动 AI数字人向更高级别进化&#xff…

JavaScript_语法--变量

1.4 变量 变量&#xff1a;一小块存储数据的内存空间 Java语言是强类型语言&#xff0c;而JavaScript是弱类型的语言 强类型&#xff1a; 在开辟变量存储空间时&#xff0c;定义了空间将来存储的数据的数据类型。只能存储固定类型的数据 弱类型&#xff1a; 在开辟变量存储空间…

GeoServer:忘记密码重置

操作步骤 1. 找到data_dir/security/usergroup/default目录下的users.xml文件&#xff0c; 2.修改password为plain:geoserver&#xff0c; 这里无论原来的密码是什么&#xff0c;改为plain:geoserver之后&#xff0c;就可以通过admin&#xff1a;geoserver默认账户密码登录了。…

3d模型有边界框怎么去除---模大狮模型网

在3D建模软件中&#xff0c;边界框通常是用来表示模型的边界和外轮廓的&#xff0c;但有时候在渲染或导出模型时可能不希望显示这些边界框。以下是一些去除3D模型边界框的方法&#xff1a; 隐藏边界框选项&#xff1a; 在大多数3D建模软件中&#xff0c;边界框的显示可以通过简…