当前位置: 首页 > news >正文

学习系统编程No.7【进程替换】

引言:

北京时间:2023/3/21/7:17,这篇博客本来昨天晚上就能开始写的,但是由于笔试强训的原因,导致时间用在了做题上,通过快2个小时的垂死挣扎,我充分意识到了自己做题能力的缺陷和运用新知识的缺陷,所以我需要把重心给转移一下了,以后做题才是我的头号目标,虽然我在很久以前可能就说过这样的话,但是这次我是认真的,就算我做题不行,但是我看代码还是行的,所以我每天必看一些做题代码,来加深自己对知识的运用,希望不久之后,能有所进步吧!哪怕只是一丝丝!所以今天我们就来学习上篇博客剩下的有关进程控制的内容,和有关进程程序替换的知识吧!

在这里插入图片描述

复习进程等待

昨天已经浅浅的了解了什么是进程等待,进程等待的目的就是为了终止僵尸进程,回收僵尸进程所占的资源,并且获得进程的退出码和退出信号,并且我们了解了进行进程等待的两个接口函数wait/waitpid,通过这两个接口,我们就可以去调用操作系统提供给我们的系统调用,这样就可以利用系统调用的形式来完成进程等待了;我们昨天已经知道使用wait接口就是用来等待一个进程的子进程,并且有代码演示,这里不多做理解,昨天我们也了解了waitpid这个接口,发现该接口有三个参数,并且其中第一个参数pid,它的作用和wait的参数差不多,本质就是为了等待一个进程,pid=0等待的是该进程的子进程,pid>0,等待的则是任意一个pid相等的进程,和第二个参数status,我们了解到,该参数是一个位图结构的参数,不单单是整形类型,本质为位图结构就是为了可以同时从一个参数上获取退出码和退出信号两个码值,第三个参数options,就是用于判断子进程是否正常终止,父进程是否继续等待的问题,所以接下来,我们就承接这上篇博客,把剩下的有关位图结构,也就是有关status参数的知识再深入学习一下,如下:

继续谈status

上篇博客,我们了解到status是一个位图结构,可以同时返回退出码和退出信号,并且退出码是由32个比特位中的后16个比特位中的次第8位构成的,退出信号是由最后7个比特位构成的(core down先不谈),所以按照这个逻辑,此时我们想要拿到,status中的退出信号和退出码是有办法的,没错,就是使用我们在C语言中所学的位运算的概念,具体这里不多做讲解(具体就是左移和右移),左移以为表示的就是该值乘2,右移一位表示的就是除2,并且还涉及到了按位或、按位与、按位异或的知识,如下图:
在这里插入图片描述

通过上述的 (status >> 8)& 0xFF、status & 0x7F 此时我们就可以获得该进程的退出码和退出信号了,但是要知道,上述获取子进程退出码和退出信号的方式,是我们自己通过位图结构的概念,通过位运算获得的,但是注意,在Linux操作系统内部,它本身是为我们提供了获取子进程退出码和退出信号的方式,如下图:
在这里插入图片描述

所以按照我们上述所说,父进程就可以通过使用waitpid接口,来调用系统调用,从而获取子进程的退出码和退出信号,但是具体在调用系统调用接口的时候,本质上这些工作还是由我们的操作系统来完成了,因为只有操作系统才有获取进程退出码和退出信号的资格,所以此时就有一个问题,就是父进程具体是如何通过操作系统来获取子进程的退出码和退出信号呢?

首先明白,无论是父进程还是子进程,它们都是一个独立的进程,所以每个进程都拥有自己的地址空间,进程pcb、页表和物理内存等资源;并且明白,子进程pcb内不仅有从父进程pcb中继承的相关属性,而且还有两个和子进程退出码和退出信号至关重要的属性 (int exit_code ,int exit_signal) ,从该属性的名字就可以看出,这两个子进程pcb属性代表的就是进程退出码和退出信号,表示的仅仅就是两个整数而已;
明白了这些之后,此时就可以回答该问题了,如下:
当子进程执行完毕之时,操作系统会将main函数对应的返回值写到该进程pcb的int exit_code当中,如果该进程异常,则将对应的退出信号写到该进程pcb的int exit_signal当中,并且最后在进程退出之后,操作系统会将该进程的pcb维护起来,所以当该子进程pcb被操作系统维护起来之后,此时父进程就可以通过调用系统接口 wait/waitpid 通过操作系统来去找到该退出进程对应的进程pcb,可以找到子进程pcb的具体原理是因为,父进程在调用waitpid接口的时候,已经把子进程的pid告诉了父进程(也就是传参的时候已经把进程子pid给给了waitpid接口),所以最后通过子进程pid,进而找到该子进程的pcb,进而找到pcb中的该子进程的退出码 int exit_code 和退出信号 int exit_signal,最后再利用waitpid中的第二个参数status(输出型参数)将退出码和退出信号返回给父进程(当然也就是上述的ret_id变量)

总:父进程获取子进程的退出码和退出信号的本质就是通过操作系统读取子进程的内核数据结构(pcb)

并且有的同学非常的好奇,就是有没有一种可能,就是父进程在等待的时候,子进程一直没有退出呢?或者说父进程在等待的时候具体是在干什么呢?

所以此时我们就借着上述问题来谈一谈,什么是阻塞等待和非阻塞轮询等待

首先我们要明白,当子进程没有退出的时候,父进程在干什么呢?
谈到这个,此时又不得不谈谈waitpid的第三个参数,options,上篇博客我们说了,这个参数的作用就是用于判断子进程是否正常终止,父进程是否继续等待问题,并且该参数我们默认给给的是一个叫 WNOHANG 的参数,具体意思:就是用于判断该子进程是否终止,如果该子进程未终止,那么此时waitpid()函数就返回0,如果该子进程终止,则返回该子进程的pid,此时就可以很好的通过这第三个参数来判断一个进程的子进程是否处于终止状态,所以明白了这点,此时就可以明白父进程是可以通过该参数来控制自己的行为,也就是上述所说的阻塞等待和非阻塞轮询等待!

谈谈父进程的阻塞等待

从上述的知识,我们可以知道,如果waitpid()函数返回0,表示的就是该子进程没有结束,子进程没有结束,那么父进程此时可以干什么呢?首先第一种情况,父进程一直在调用waitpid进行等待 ,此时的一直进行等待,本质上表示的就是阻塞等待,也就是表示父进程此时从本来的正常运行状态变成了一个阻塞状态,变成了一个等待子进程的状态;所以我们可以明白,当父进程处于阻塞状态之时,父进程是不在CPU的运行队列之中,而是在某一个阻塞队列之中;并且此时再深入理解,还可以明白,父进程处于阻塞等待之时,子进程处于运行状态,那么等子进程执行完之后呢?父进程如何从阻塞状态重新变成运行状态来为子进程收尸呢? 谈到这个问题,此时就又涉及到了,子进程的进程pcb,在子进程pcb内部,我们可以理解存在一个指向父进程的指针,所以当子进程一但退出(注意此时父进程肯定是不在运行队列,而是在阻塞队列的),此时子进程就可以利用pcb中指向父进程的指针,重新找到父进程(唤醒),此时父进程检测到之后(被唤醒),就又会从阻塞状态变成运行状态,然后被操作系统又重新链接到运行队列之中,最后父进程继续执行 wait/waitpid,最终就将子进程给回收

所以上述就是父进程阻塞等待全过程

谈谈父进程的非阻塞轮询等待

搞懂了上述父进程的阻塞等待,此时就可以明白父进程肯定还有一种非阻塞等待(毕竟我是父进程,你是小子,我才是老子,我凭什么一定要等你呢?)所以,此时还是同理,当我们通过waitpid()函数的返回值,判断出该子进程还没有结束时,我们就可以让父进程不需要一直进行等待(不需要一直处于阻塞状态),具体代码如下:
在这里插入图片描述
所以此时通过上述的代码,我们就可以很好的理解什么是父进程的阻塞等待和非阻塞轮询等待了,并且可以将其很好的抽象成一个生活中场景,如下:

场景一:
周末出去玩,李四打电话给张三,问张三去不去,此时张三说去,但是要准备一下(子进程未终止),李四说好,我等你(父进程等待),但是电话别挂(阻塞等待
场景二:
如法炮制,还是周末出去玩,李四打电话给张三,问张三去不去,张三还是去,并且也还是需要准备一下,此时李四还是说好,但是此时李四却把电话给挂断了,在电话挂断之后,李四想了想也去准备了一下,过了一会之后,李四准备的差不多了,就又打电话给张三,张三却还是没有准备好,此时李四就又把电话挂了,又去准备东西了,同理,李四一直打电话问张三好了没有(非阻塞轮询等待),而张三却一直没好,直到最后好了(子进程终止)

所以上述的两种情况(李四给张三打电话,表示的就是父进程使用waitpid()等待子进程,)第一种情况电话不挂表示的就是父进程处于阻塞队列,这种情况也就是阻塞调用;第二种情况,表示我打完电话,问完情况,我们把电话挂掉,此时表示的就是父进程不处于阻塞等待,也就是表示该调用,此时是属于非阻塞调用,(非阻塞调用的好处,就是父进程可以干自己想干的事情,例:准备自己的东西)

所以上述的两种场景就是父进程阻塞等待和非阻塞等待的两个现实生活抽象场景,可以非常好的凸显出父进程等待的两种情况

总:父进程可以通过参数进行判断,然后来控制自己的行为,也就是上述所说的阻塞等待和非阻塞轮询等待!

总结:进程控制的三个话题:进程创建、进程等待、进程终止此时就算告一段落啦!现在让我们呢一起开始新知识的学习吧!

进程替换

搞定了上述的知识,此时我们就进入今天的正菜,什么是进程替换,在弄懂什么是进程替换之前,我们引入一个问题,就是为什么要创建子进程?所以我们要明白,我们创建子进程的目的:就是为了让子进程帮我执行某些特定的任务,但是此时让子进程去执行某些代码的时候,就会出现如下两种情况:

1. 让子进程执行父进程的部分代码,也就是一个可执行文件中的部分代码(这些代码本质都是属于父进程)
2. 子进程想要执行一个全新的属于自己的代码(本质就是不想执行父进程的代码)

所以碰到上述第二种情况,此时就可以引出我们的新概念:进程程序替换

如下图:就是一个最简单的进程程序替换demo
在这里插入图片描述
所以使用execl接口的本质就是进行进程的切换,让该可执行文件形成的进程去执行Linux操作系统中bin目录下的ls指令(ls可执行文件),也就是表明,当我们使用了进程替换函数时,我们可以在任意一个可执行文件中执行任意的指令,本质是进程替换

总:进程程序替换,就是让一个进程去执行另一个在磁盘(Linux操作系统下的bin目录)当中的程序(可执行文件),把一个新的程序运行起来

程序替换的原理

首先明白,创建一个进程,该进程肯定是有对应的pcb、页表、地址空间和物理内存,所以我们就从这些进程的必要条件入手,来看看进程替换到底是什么,如下图:
在这里插入图片描述

从图中,我们可以了解到以下知识:
当前进程的代码等数据是需要通过页表映射到物理内存的特定区域,所以当一个进程执行了部分代码后,当其执行到了系统调用接口(execl等……),进程此时就会根据我所传入的程序的路径(Linux操作系统下的bin目录)和我要执行的程序的名称和选项(“ls” “a”),然后把磁盘当中(通过对应的路径找到bin)的其它的程序的代码和数据加载到内存,最后用新程序的代码来替换我们原程序中的代码,用新程序的数据来替换原程序中的数据(这个过程不是在地址空间完成的,是在物理内存中完成的);所以总的来说: 程序在替换时,就相当于原进程的内核数据结构不变,把原进程在物理内存中的代码和数据替换为新进程的代码和数据(从磁盘中加载),此时这个行为的发生就叫做程序替换

并且要明白,进程在进行程序替换的时候,是没有创建新的进程的,本质还是程序替换的本质。

并且此时明白,可以进行进程程序替换的接口一共有7个,此时我们已学其一,剩下的6个都是同理,只是在使用上不同而已,所以我们今天浅浅的摸了一下程序替换就行了(明天要晨跑),今天博客就这样吧!撤了!

补充小知识点:

fork函数的两个返回值浅显理解:一个是父进程返回子进程的pid,一个是子进程没有子进程所以返回0,感兴趣的同学,可以参看下面这个链接;为什么fork有两个返回值

北京时间:2023/3/21/22:45
在这里插入图片描述

总结:像程序替换(execl)这样的系统接口,等我们学到了文件操作和网络的时候,我们就经常会谈到,并且会用到更多,所以革命还未胜利,挑战任在继续,加油吧,少年!

相关文章:

学习系统编程No.7【进程替换】

引言: 北京时间:2023/3/21/7:17,这篇博客本来昨天晚上就能开始写的,但是由于笔试强训的原因,导致时间用在了做题上,通过快2个小时的垂死挣扎,我充分意识到了自己做题能力的缺陷和运用新知识的缺…...

【3.22】操作系统内存管理(整理)、Java并发

3. 内存管理 为什么要有虚拟内存? 我们想要同时在内存中运行多个程序,就需要把进程所使用的地址隔离,所以使用了虚拟内存。简单来说,虚拟内存地址是程序使用的内存地址。物理内存地址是实际存在硬件里面的地址。 操作系统为每个…...

电脑文件丢失怎么找回来

电脑文件丢失怎么找回来?最近打开电脑时,它启动得很慢。刚刚开始我没有没在意,就重启了当我再次打开电脑时,发现桌面上的文件消失了,面对这种意外情况,有什么办法可以快速找到呢? 电脑文件丢失后,想要找回…...

Python(白银时代)——面向对象

基本概念 面向过程 是早期的一个编程概念,类似函数,但是没有返回值 具体做法: 把完成某个需求的所有步骤,从头到尾 逐步实现 将某些功能独立的代码 封装成一个又一个 函数 然后顺序调用不同的函数 特点: 注重 步骤…...

Python流星雨代码

前言 用Python画场流星雨看看,源码见文末公众号哈。 流星类 def __init__(self): self.r ra.randint(50,100) self.t ra.randint(1,3) self.x ra.randint(-2000,1000) #流星的横坐标 self.y ra.randint(0,500) #流星…...

Java语言-----类与对象的秘密

目录 前言 一、类与对象的介绍 二、类的实例化 三.类与对象的使用方法 3.1对象的初始化 3.2内存显示图 四.this的使用方法 总结 😽个人主页: tq02的博客_CSDN博客-C语言,Java领域博主 🌈理想目标:努力学习,向Java进…...

大数据处理学习笔记2.1 初识Spark

文章目录零、本节学习目标一、Spark的概述(一)Spark的组件1、Spark Core2、Spark SQL3、Spark Streaming4、MLlib5、Graph X6、独立调度器、Yarn、Mesos(二)Spark的发展史1、发展简史2、目前最新版本二、Spark的特点(一…...

太强了,英伟达面对ChatGPT还有这一招...

大家好,我是 Jack。 今年可谓是 AI 元年,ChatGPT、AIGC、VITS 都火了一波。 我也先后发布了这几期视频: 这是一个大模型的时代,AI 能在文本、图像、音频等领域大放异彩,得益于大模型。而想要预训练大模型&#xff0c…...

【微服务】—— Nacos注册中心

文章目录一、Nacos 注册中心的设计原理1、数据模型2、数据⼀致性3、负载均衡4、健康检查二、Nacos 注册中心服务数据模型1、服务(Service)和服务实例(Instance)1)定义服务2)服务元数据3)定义实例…...

GPT-4是个编程高手,真服了!

上周给大家发了一个GPT-4教数学的介绍,很多人都被震撼了,感觉有可能在教育行业引发革命。它在编程领域表现如何?先不说能否替代程序员,这个还有待更多的测试和反馈,我想先试试它能不能像教数学那样教编程。我找了个Jav…...

基于深度学习的车型识别系统(Python+清新界面+数据集)

摘要:基于深度学习的车型识别系统用于识别不同类型的车辆,应用YOLO V5算法根据不同尺寸大小区分和检测车辆,并统计各类型数量以辅助智能交通管理。本文详细介绍车型识别系统,在介绍算法原理的同时,给出Python的实现代码…...

【蓝桥杯C++】3月21日刷题集训ABC-附百分代码,一目了然

目录 刷题集训 A Day 1 成绩分析 Day 1 饮料换购 刷题集训 B Day 1 分巧克力 Day 1 递增三元组 Day 1 小明的衣服 刷题集训 C Day 1 数字三角形 Day 1 跳跃 Day 1 蓝太子序列 刷题集训 A Day 1 成绩分析 题目描述 小蓝给学生…...

HBase高手之路4-Shell操作

文章目录HBase高手之路3—HBase的shell操作一、hbase的shell命令汇总二、需求三、表的操作1.进入shell命令行2.创建表3.查看表的定义4.列出所有的表5.删除表1)禁用表2)启用表3)删除表四、数据的操作1.添加数…...

聊聊SQL审计功能

什么是sql审计SQL审计是指对SQL语句的执行情况进行记录和追踪,包括SQL语句的执行时间、执行次数、执行结果等信息。通过SQL审计,可以对数据库的使用情况进行监控和管理,包括对SQL注入、非法访问、数据泄露等安全问题的检测和防范,…...

Markdown常用语法(字体颜色)

一些不错的帖子 写CSDN博客时&#xff0c;调节字体大小、颜色及其他样式的常用操作方法 设置字体颜色 使用<font>标记&#xff1a; 这是红色字体&#xff1a;<font colorred>我是红色的字体</font>显示效果如下&#xff1a; 这是红色字体&#xff1a;我是…...

I2C模块理解

I2C模块理解 文章目录I2C模块理解1.配置I2C2.信号3.数据传输3.1主机发送3.2主机接收3.3从机发送3.4从机接收4.中断传输5.Aardvark1.配置I2C I2C的特征 只需要两条公共总线&#xff08;线&#xff09;即可控制I2C网络上的任何设备无需像UART通信那样事先约定数据传输速率。因此…...

手把手教你使用--常用模块--HC05蓝牙模块,无线蓝牙串口透传模块,(实例:手机蓝牙控制STM32单片机点亮LED灯)

最近在学STM32&#xff0c;基本的学完了&#xff0c;想学几个模块来巩固一下知识&#xff0c;就想到了蓝牙模块。玩啥好难过有很多博客教怎么连的&#xff0c;但自己看起来还是有点糊涂。模块的原理和知识点我就不讲解了&#xff0c;这里我主要手把手记录一下我是如何对蓝牙模块…...

MyBatis高频面试题

目录 1、Mybatis中#和$的区别 2、Mybatis的编程步骤是什么样的 3...

Redis基础篇

redis的三大特点&#xff1a; 支持多数据类型&#xff0c;支持持久化&#xff0c;单线程 多路IO复用 对键操作的命令&#xff1a; keys * 查看当前库所有key exists key 判断key是否存在 del key 删除 unlink key 非阻塞删除&#xff0c;异步删除 expire key …...

unity的C#学习——静态常量和动态常量的定义与使用

定义常量 在C#中&#xff0c;常量是一种不可改变的量&#xff0c;一旦被定义&#xff0c;其值就不能被修改。C#中有两种类型的常量&#xff0c;静态常量和动态常量。 1、静态常量的定义 静态常量是在编译时就已经确定其值的常量&#xff0c;使用const关键字定义。由于在编译…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...