【Linux进程】进程控制(上) {进程创建:fork的用法,fork的工作流程,写时拷贝;进程终止:3种退出情况,退出码,常见的退出方法}

一、进程创建

在这里插入图片描述

1.1 fork的初步认识和基本使用

在linux中fork函数是非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

#include <unistd.h>
pid_t fork(void);

返回值:子进程中返回0,父进程返回子进程pid,创建失败返回-1

详细内容请看另一篇文章:
【Linux进程】进程的基本概念 {PCB结构体,进程表,Linux中的task_struct,查看进程,获取进程PID,使用fork创建子进程}


1.2 fork的具体工作流程

在这里插入图片描述

进程调用fork,当控制转移到内核中的fork代码后,内核做:

  1. 创建:分配新的内核数据结构和内存块(用于加载代码和数据)给子进程
  2. 初始化:将父进程内核数据结构的部分内容拷贝至子进程
  3. 组织管理:添加子进程到系统进程列表当中,交由操作系统管理进程。
  4. 开始执行:fork返回,开始调度器调度,子进程开始执行。

1.3 写时拷贝

在这里插入图片描述

  1. 在进行写入操作之前,父子进程的页表会将他们的地址空间映射到同一段物理内存;
  2. 同时将所有页表项暂时设置成只读权限,表示该页表项指向的物理内存被父子共享不能随意修改。
  3. 当父子任意一方试图进行写入时,与页表项的只读权限发生冲突,操作系统才会将被写入的页表项指向的物理内存拷贝分离;
  4. 并将该页表项的只读权限取消,表示该页表项指向的物理内存被一个进程独占可以直接进行写入。

为什么要进行写时拷贝?

  • 由于进程具有独立性,创建子进程时必须为其分配独有的内核数据结构。

  • 但在子进程创建过程中,并不会为其重新加载一份代码和数据,起初父子进程会共享同一份代码和数据。

  • 由于代码的只读属性,父子共享是没有问题的。但是数据可以被修改,所以必须通过某种方式进行分离。

  • 为什么不在进程创建时直接拷贝分离呢?原因有二:

    1. 分配的数据空间可能不会被立刻用到,空间闲置就是对内存资源的浪费。
    2. 有些数据可能根本不会被子进程访问,或者在运行过程中只会被读取,对于这样的数据没有拷贝分离的必要。
  • 基于这样的原因,操作系统选择了写时拷贝技术将父子进程的数据进行分离,保证了进程的独立性。写时拷贝是一种延时申请技术,可以提高整机内存的使用率

父子进程共享的代码是fork之后的还是所有的?

当然是所有代码都会被父子共享。

  1. 事实上,我们的代码通过编译就变成了二进制指令。程序加载到内存后,每条指令都会有对应的地址。

  2. 由于现代CPU采用并发控制,所有进程在执行过程中都有可能被中断,CPU转而去执行其他进程。当CPU资源再次分配到该进程时,进程当然需要从之前的位置继续执行。进程的执行位置记录在进程上下文中的PC值中,即程序计数器PC(Program Counter)。它是CPU内的寄存器数据,专门用于记录下一条要执行的指令的地址。

  3. 实际上所有的代码都会被父子进程共享。但在创建子进程时,父进程的进程上下文也会拷贝给子进程。由于PC值相同,父子进程会从fork之后的同一个位置开始向下执行。所以看起来就像是共享fork之后的代码一样。当然如果你愿意,子进程也可以去执行fork之前的代码。


1.4 fork的常规用法

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

1.5 fork调用失败的原因

  1. 系统资源不足:当系统中可用的资源(如内存、进程表项等)不足以支持新的进程创建时,fork调用会失败。

  2. 进程数量限制:操作系统可能对同时运行的进程数量进行限制,当已达到最大进程数量时,fork调用会失败。

  3. 系统错误:可能存在其他系统错误导致fork调用失败,例如操作系统内部错误或者硬件故障。

测试代码:父进程不断创建子进程,子进程死循环不退出,直至创建失败!

#include <stdio.h>    
#include <unistd.h>    
    
int main(){    
  int max_proc = 0;    
  while(1)    
  {    
    pid_t id = fork();    
    if(id == -1)    
    {    
      perror("fork error:");    
      printf("max_proc:%d\n", max_proc);    
      return 1;    
    }    
    else if(id == 0)    
    {    
      while(1){    
        sleep(1);    
      }    
    }                                                                                                                            
    else    
    {      
      ++max_proc;    
    }       
  }      
}

运行结果:
在这里插入图片描述
我的虚拟机配置较低,只创建了4093个进程就造成了系统资源不足的问题。此时系统处于崩溃边缘,很多命令无法正常运行。


二、进程终止

在这里插入图片描述

进程终止时会释放占用的系统资源,包括CPU资源和内存空间(内核数据结构和对应的数据和代码),最后结束进程。

2.1 进程的退出情况

  1. 代码跑完,结果正确
  2. 代码跑完,结果不正确
  3. 代码没有跑完,程序崩溃

其中,代码跑完结果是否正确及错误原因通过退出码返回给上一级进程(父进程)

如果程序崩溃,崩溃原因通过退出信号返回给上一级进程


2.2 进程退出码

  1. 进程退出码返回给上一级进程,是用来评判该进程执行结果用的,可以忽略。

  2. 进程退出码用0表示运行成功且结果正确。非0表示运行结果不正确。

  3. 非0值有很多个用于表示不同的错误原因,当程序运行结束后方便定位错误。

  4. 在Linux系统中,退出码是无符号整数,占8位,范围[0,255]。

提示:使用echo $?获取最近一个进程执行完毕后的退出码。

得到退出码后如何将退出码转换成错误描述呢?

在这里插入图片描述

利用strerror函数打印0~15错误码的字符串描述:

在这里插入图片描述

ls 和 kill命令在执行时同样也是进程,进程退出就有退出码:

  1. ls命令的错误描述与其退出码相对应,说明他使用的是库函数的预置退出码方案。

  2. kill命令的错误描述与其退出码不对应,说明他使用的是自定义退出码方案。

  3. 我们的程序可以使用库函数预置的退出码解释方案。当然,如果你愿意也可以自己设计一套退出码解释方案!但是不要随意制定退出码方案,否则会导致误解退出码含义。


2.3 进程退出信号

进程崩溃

在这里插入图片描述

  1. 程序崩溃,崩溃原因通过退出信号返回给上一级进程,退出信号在下一节 “进程等待” 章节的 “进程状态” 部分讲解
  2. 程序崩溃时,退出码无意义。因为return/exit没有被执行,此时的退出码是一个随机值。

2.4 进程常见的退出方法

2.4.1 return语句

  1. return是C/C++语句

  2. 其他函数内的return语句表示该函数退出。

  3. 而main函数内的return语句表示进程退出,return后跟的数字就是退出码。


2.4.2 _exit函数

在这里插入图片描述

  1. _exit是Linux系统调用
  2. _exit在任何地方调用,都表示直接终止进程!
  3. _exit直接终止进程,不考虑缓冲区的问题。

2.4.3 exit函数

在这里插入图片描述

  1. exit是C库函数,底层封装_exit系统调用。

  2. exit在任何地方调用,都表示直接终止进程!

  3. exit在终止进程之前会将缓冲区中的数据刷新到显示器上。

  4. 推荐使用exit终止进程

在这里插入图片描述

注意:我们之前讨论的缓冲区,实际是由C标准库为我们维护的,而不是操作系统。

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

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

相关文章

ORB-SLAM2学习笔记5之EuRoc、TUM和KITTI开源数据运行ROS版ORB-SLAM2生成轨迹

文章目录 0 引言1 数据预处理1.1 EuRoc数据1.2 TUM数据1.3 KITTI数据 2 代码修改2.1 单目2.2 双目2.3 RGB-D 3 运行ROS版ORB-SLAM23.1 单目3.2 双目3.3 RGB-D ORB-SLAM2学习笔记系列&#xff1a; 0 引言 ORB-SLAM2学习笔记1已成功编译安装ROS版本ORB-SLAM2到本地&#xff0c;本…

SQL高级教程第三章

SQL CREATE DATABASE 语句 CREATE DATABASE 语句 CREATE DATABASE 用于创建数据库。 SQL CREATE DATABASE 语法 CREATE DATABASE database_name SQL CREATE DATABASE 实例 现在我们希望创建一个名为 "my_db" 的数据库。 我们使用下面的 CREATE DATABASE 语句&…

2023云曦期中复现

目录 SIGNIN 新猫和老鼠 baby_sql SIGNIN 签到抓包 新猫和老鼠 看到反序列化 来分析一下 <?php //flag is in flag.php highlight_file(__FILE__); error_reporting(0);class mouse { public $v;public function __toString(){echo "Good. You caught the mouse:&…

5.1.tensorRT基础(2)-正确导出onnx的介绍,使得onnx问题尽量少

目录 前言1. 正确导出ONNX总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 基础-正确导出 onnx 的介绍&#xff0…

飞书ChatGPT机器人 – 打造智能问答助手实现无障碍交流

文章目录 前言环境列表1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 前言 在飞书中创建chatGPT机器人并且对话&#xff0c;在下面操作步骤中…

基于DeepFace模型设计的人脸识别软件

完整资料进入【数字空间】查看——baidu搜索"writebug" 人脸识别软件(无外部API) V2.0 基于DeepFace模型设计的人脸识别软件 V1.0 基于PCA模型设计的人脸识别软件 V2.0 更新时间&#xff1a;2018-08-15 在观看了吴恩达老师的“深度学习课程”&#xff0c;了解了深…

2023/7/23周报

目录 摘要 论文阅读 1、题目和现存问题 2、问题阐述及相关定义 3、LGDL模型框架 4、实验准备 5、实验过程 深度学习 1、GCN简单分类任务 2、文献引用数据分类案例 3、将时序型数据构建为图数据格式 总结 摘要 本周在论文阅读上&#xff0c;对基于图神经网络与深度…

【蓝牙AVDTP A2DP协议】

蓝牙AVDTP A2DP 一.AVDTP1.1 AVDTP概念1.2 Source Sink整体框架1.3 AVDTP术语1.3.2 Stream1.3.2 SRC and Sink1.3.3 INT and ACP1.3.4 SEP&#xff1a; 1.4 AVDTP体系1.4.1 体系概括1.4.2 Transport Services 1.5 Signaling Procedures1.5.1 General Requirements1.5.2 Transac…

关于Arduino IDE库文件存放路径问题总结(双版本)

在开发过程中,如果不注意,库文件存放路径很乱,如果在转移系统环境时,容易忘记备份。编译过程中出现多个可用引用包的位置,为了解决这些问题,要明白各文件夹的默认路径在哪,区别在哪,如有了解不对的地方请指正。 IDE安装目录(默认C盘,自定义可以其他盘符下)IDE升级可…

2023华为OD统一考试(B卷)题库清单(持续收录中)以及考点说明

目录 专栏导读2023 B卷 “新加题”&#xff08;100分值&#xff09;2023Q2 100分2023Q2 200分2023Q1 100分2023Q1 200分2022Q4 100分2022Q4 200分牛客练习题 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#xff09;》。 刷的越多&…

PALO ALTO NETWORKS 的新一代防火墙如何保护企业安全

轻松采用创新技术、阻止网络攻击得逞并专注更重要的工作 IT 的快速发展已改变网络边界的面貌。数据无处不在&#xff0c;用户可随时随地从各类设备访问这些数据。同时&#xff0c;IT 团队正在采用云、分析和自动化来加速新应用的交付以及推动业务发展。这些根本性的转变带来了…

11 简单的Thymeleaf语法

11.1 spring-boot环境准备 重要依赖&#xff1a; <!--thymeleaf--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> 11.2 转发消息不转义 就是如…

Vue3状态管理库Pinia——核心概念(Store、State、Getter、Action)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

iClient3D for CesiumWebGL入门之使用vscode以服务方式运行调试

作者&#xff1a;超图研究院技术支持中心-于丁 iClient3D for Cesium&WebGL入门之使用vscode以服务方式运行调试 相信大家第一次使用SuperMap iClient3D for Cesium或SuperMap iClient3D for WebGL的时候&#xff0c;都遇到过和我一样的事情&#xff1a; 在文件夹中直接打…

Android Studio 提示 Failed to initialize editor问题的解决

Android Studio 从2018的版本升级到2021年的版本后&#xff0c;无法预览xml。我查了很久&#xff0c;最后发现是Gradle的版本和工具不匹配&#xff0c;按照开发工具的提示&#xff0c;升级版本即可&#xff0c;我的是从3.2.1升级到了4.2.2

生产者消费者模型

生产者消费者模型 文章目录 生产者消费者模型概念原则优点 基于BlockingQueue的生产者消费者模型BlockingQueue模拟实现单生产者消费者模型基于计算任务和存储任务的生产者消费者模型 概念 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题生产者和消费者彼…

C++ 单例模式(介绍+实现)

文章目录 一. 设计模式二. 单例模式三. 饿汉模式四. 懒汉模式结束语 一. 设计模式 单例模式是一种设计模式 设计模式(Design Pattern)是一套被反复使用&#xff0c;多数人知晓的&#xff0c;经过分类的&#xff0c;代码设计经验的总结。 为什么要有设计模式 就像人类历史发展会…

python机器学习(三)特征预处理、鸢尾花案例--分类、线性回归、代价函数、梯度下降法、使用numpy、sklearn实现一元线性回归

K-近邻算法(K-Nearest Neighboor) 特征预处理 数据预处理的过程。数据存在不同的量纲、数据中存在离群值&#xff0c;需要稳定的转换数据&#xff0c;处理好的数据才能更好的去训练模型&#xff0c;减少误差的出现。 标准化 数据集的标准化对scikit-learn中实现的大多数机器…

遥感目标检测(3)-DAL(Dynamic Anchor Learning for Object Detection)

目录 一、概述 二、背景 三、建议 1、旋转RetinaNet 2、动态锚框分布 3、匹配敏感损失 四、实验 一、概述 由于选择正样本锚框进行回归&#xff0c;不一定能够定位真实的GT&#xff0c;而部分负样本回归甚至可以回归到真实的GT&#xff0c;说明相当多的负样本锚框有着准…

【自启动配置】Ubuntu 设置开机自启动脚本

Ubuntu 开机运行的脚本和当前操作系统运行的级别有关&#xff0c;OS 的运行级别大概分为七个 目录 1、查看 OS 运行级别 2、创建自启动脚本 3、添加软链接 1、查看 OS 运行级别 输入命令 runlevel 查看当前系统运行级别。当前系统的运行级别为 5 2、创建自启动脚本 在 /et…