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

【Linux】进程替换

文章目录

      • 进程程序替换
      • 替换原理
      • 替换函数
      • 函数返回值
      • 函数命名理解
          • 在makefile文件中一次生成两个可执行文件
    • 总结:
      • 程序替换时运行其它语言程序

进程程序替换

程序要运行要先加载到内存当中 , 如何做到? 加载器加载进来,然后程序替换

为什么? ->冯诺依曼 因为CPU读取数据的时候只能和内存打交道 CPU执行程序的时候离内存最近.CPU要从内存拿数据和代码,前提条件是外设当中的可执行程序加载到内存中


替换原理

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支), 那如果我们想让子进程执行一个“全新”的程序要怎么做呢? 我们就需要通过程序替换实现

子进程往往要调用一种exec*函数以执行另一个程序

  • 当进程调用一种exec*函数时**,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行**
  • 调用exec并不创建新进程,所以调用exec前后该进程的id并未改变

什么叫做进程程序替换?

进程不变,仅仅替换当前进程的代码和数据的技术,并没有创建新的进程(所以进程的id没有改变) 叫做进程程序替换

image-20220528115434428

老程序的壳子不变,把新程序的代码和数据替换进去, 进程替换是把磁盘上的程序加载到内存中


进程程序替换时有没有创建新的进程?

进程程序替换之后,该进程对应的PCB.进程地址空间以及页表等数据结构都没有发生改变,只是进程在物理内存当中的数据和代码发生了改变,所以并没有创建新的进程,而且进程程序替换前后该进程的pid并没有改变

程序替换的本质是什么?

本质是把程序的代码+数据加载到特定进程的上下文中, C/C++程序要运行,必须要先加载到内存中

程序运行是如何加载到内存中的呢?

通过加载器,加载器的底层原理就是一系列的exec*程序替换函数

直接打开和程序替换打开有什么区别?

直接打开是要形成新的进程,而进程替换不形成新进程, ->没有PCB的创建,先有的进程然后才能执行程序替换


image-20220528114619079


我们fork子进程,然后让子进程进行程序替换,会影响父进程吗? 父子代码是共享的吗?

父进程不会受影响,因为进程是具有独立性的!没有修改数据的时候,父子共享代码,修改就会发生写时拷贝 进程替换会更改代码区的代码,要发生写时拷贝,这样就可以让子进程执行全新的程序

子进程刚被创建时,与父进程共享代码和数据,但当子进程需要进行进程程序替换时,也就意味着子进程需要对其数据和代码进行写入操作,这时便需要将父子进程共享的代码和数据进行写时拷贝,此后父子进程的代码和数据也就分离了,因此子进程进行程序替换后不会影响父进程的代码和数据

image-20220528114955157

image-20220528115016987


替换函数

其实有六种以ex为ec开头的函数,统称exec函数

image-20220528115827690

#include <unistd.h>`
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

函数返回值

  • 这些函数如果调用成功 则加载新的程序从启动代码开始执行,不再返回.
  • 如果调用出错则返回-1
  • 所以exec函数只有出错的返回值而没有成功的返回值, exec系列的函数,只要返回了,就一定是调用失败

关于exec*系列函数的返回值:

只要进程的程序替换成功,就不会执行后序的代码, 所以,exec*函数成功是不需要进行返回值检测,只要返回了,就一定是因为调用失败了,直接退出程序就好

调用失败的例子:

image-20220528120643822

如何证明它是调用失败呢?

image-20220528121336747


函数命名理解

上述函数名看起来很容易混乱,我们理解他们的命名含义就好记了

替换函数接口后后缀含义
l(list)参数采用列表方式
v(vector)参数采用数组方式
p(path)自动搜索环境变量PATH,进行程序查找
e(env)自己维护环境变量,或者说自定义环境变量,可以传入自己设置的环境变量

函数名参数格式是否带路径是否使用当前环境变量
execl列表
execlp列表
execle列表否,需自己组装环境变量
execv数组
execvp数组
execve数组否,需自己组装环境变量

事实上,只有execve才是真正的系统调用,其它五个函数最终都是调用的execve,所以execve在man手册的第2节,而其它五个函数在man手册的第3节,也就是说其他五个函数实际上是对系统调用execve进行了封装,以满足不同用户的不同调用场景的

  • 手册3:代表库函数 手册2:代表系统调用

用一张图描述exec系列函数之间的关系:

image-20220528155208845


execl

int execl(const char *path, const char *arg, ...)

第一个参数是要执行程序的路径,第二个后面的是可变参数列表,表示你要如何执行这个程序, 注意以NULL为参数传递的结尾

后缀为l:即参数用列表传递

image-20220528121940711

例子:

execl("/usr/bin/ls","ls","-a","-l",NULL);//相当于执行ls -a -l

image-20220528151816035

执行结果:

image-20220528151828206

execv

int execv(const char *path, char *const argv[])

第一个参数是要执行程序的路径,第二个参数是一个指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾

后缀为v:即参数用数组传递

//例子
char* argv[] = {"ls","-a","-l",NULL};
execv("/usr/bin/ls",argv);//相当于执行ls -a -l

使用例子:

main函数是可以携带参数的,argv是一个指针数组,指针指向命令行参数字符串,我们可以理解为:通过exec函数,把argv给了ls程序

image-20220528165703983


execlp && execvp

后缀为p:表示会自动在环境变量PATH中搜索,只需要直到程序名即可

**int execlp(const char file, const char arg, …)

第一个参数是要执行程序的名字(只需要写名称,不需要带路径,会自动找),第二个参数是可变参数列表,表示你要如何执行这个程序,并以NULL结尾

//例子:
execlp("ls","ls","-a","-l",NULL); //相当于执行ls -a -l
//第一个ls表示你要执行谁,execlp会自动在环境变量PATH中根据这个程序名搜索这个程序在什么位置
//后面的ls表示我们要如何执行它

例子:

image-20220528165807115

**int execvp(const char file, char const argv[])

第一个参数是要执行程序的名字,第二个参数是一个指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾

//例子
char* argv[] = {"ls","-a","-l",NULL};
execvp("ls",argv);//相当于执行ls -a -l

例子:

image-20220528165828107


execle && execve

后缀为e:表示会自己维护环境变量,用自己设置的环境变量

**int execle(const char *path, const char arg, …,char const envp[])

第一个参数是要执行程序的路径,第二个参数是可变参数列表,表示你要如何执行这个程序,并以NULL结尾,第三个参数是你自己设置的环境变量

//例如有两个文件:myload 和myexe,如果我们在myload中设置了环境变量,在myexe文件就可以使用该环境变量//myload:
char* env[] = {"MYPATH:hello world",NULL};
execle("./myexe","myexe",NULL,env)  //注意这里先传NULL结尾 再传env
// 因为要执行程序所在的位置已经找到了,所以第二个参数可以写成:./myexe 也可以直接写成myexe
//myexe
可以使用myload文件中的环境变量MYPATH

如果我们直接执行myexe: 默认使用的是系统的环境变量

image-20220530204412080

我们运行myload去运行myexe,执行的就是我们导入的环境变量

image-20220528165944420

**int execve(const char *path, char const argv[], char const envp[])

第一个参数是要执行程序的路径,第二个参数传你要怎么执行的,是一个指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾,第三个参数是你自己设置的环境变量

//例如有两个文件:myload 和myexe,如果我们在myload中设置了环境变量,在myexe文件就可以使用该环境变量//myload:
char* env[] = {"MYPATH:hello world",NULL};
char* argv[]={"myexe",NULL};
execve("./myexe",argv,env);//myexe
可以使用myload文件中的环境变量MYPATH,MYVAL

image-20220530204319311exec*也可也调用我们自己的程序


在makefile文件中一次生成两个可执行文件

makefile默认会形成在依赖关系当中形成第一个它所碰到的依赖文件 (makefile默认会形成第一个碰到的目标文件)

那么如何在一个makefile文件中一次形成两个可执行文件呢?

.PHONY:all
all:myload myexemyload:myload.cgcc -0 $@ $^ -std=c99
myexe:myexe.cgcc -0 $@ $^ -std=c99.PHONY:clear
clear:	
rm -f myload myexe

image-20220528165459707

解析:利用伪目标总是被执行的特点, all依赖的是myexe和myload, 因为all 没有依赖方法,所以不会生成all. 但是因为有依赖文件,所以makefile在执行的时候,一定想先形成的是all,形成all就得先形成myexe和myload. 所以会分别执行myexe和myload的gcc代码 而因为all没有依赖方法,所以形成myexe和myload之后,并不会再形成all

如何我们想形成5个呢?

只需要把依赖文件往all后面不断去添加, all : my1 my2 my3 然后后面再给依赖关系和依赖方法


总结:

所以的接口,看起来没有太大的差别,只有一个就是参数的不同,为什么会有这么多接口?是为了满足不同的应用场景


程序替换时运行其它语言程序

例子:

image-20220528152047190

想要执行的是/usr/bin/python3路径下的python程序, 如何执行呢? python test.py

相关文章:

【Linux】进程替换

文章目录进程程序替换替换原理替换函数函数返回值函数命名理解在makefile文件中一次生成两个可执行文件总结:程序替换时运行其它语言程序进程程序替换 程序要运行要先加载到内存当中 , 如何做到? 加载器加载进来,然后程序替换 为什么? ->冯诺依曼 因为CPU读取数据的时候只…...

LeetCode171-Excel表列序号(进制转换问题)

LeetCode171-Excel表列序号1、问题描述2、解题思路&#xff1a;进制转换3、代码实现1、问题描述 给你一个字符串columnTitle,表示Excel表格中得列名称。返回该列名称对应得列序号。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 …...

React SSR

ReactDOMServer 参考链接&#xff1a;https://zh-hans.reactjs.org/docs/react-dom-server.html ReactDOMServer 对象允许你将组件渲染成静态标记。通常&#xff0c;它被使用在 Node 服务端上 // ES modules import * as ReactDOMServer from react-dom/server; // CommonJS v…...

如何系统地优化页面性能

页面优化&#xff0c;其实就是要让页面更快地显示和响应。由于一个页面在它不同的阶段&#xff0c;所侧重的关注点是不一样的&#xff0c;所以如果要讨论页面优化&#xff0c;就要分析一个页面生存周期的不同阶段。 通常一个页面有三个阶段&#xff1a;加载阶段、交互阶段和关…...

Vulnhub 渗透练习(八)—— THE ETHER: EVILSCIENCE

环境搭建 环境下载 靶机和攻击机网络适配都选 NAT 即可。 信息收集 主机扫描 两个端口&#xff0c;22 和 80&#xff0c;且 apache httpd 2.4.0~2.4.29 存在换行解析漏洞。 Apache HTTPD是一款HTTP服务器&#xff0c;它可以通过mod_php来运行PHP网页。其2.4.0~2.4.29版本中…...

华为OD机试题 - 水仙花数 2(JavaScript)| 代码+思路+重要知识点

最近更新的博客 华为OD机试题 - 字符串加密(JavaScript) 华为OD机试题 - 字母消消乐(JavaScript) 华为OD机试题 - 字母计数(JavaScript) 华为OD机试题 - 整数分解(JavaScript) 华为OD机试题 - 单词反转(JavaScript) 使用说明 参加华为od机试,一定要注意不要完全背…...

字符设备驱动基础(二)

目录 一、五种IO模型------读写外设数据的方式 二、阻塞与非阻塞 三、多路复用 3.1 应用层&#xff1a;三套接口select、poll、epoll 3.2 驱动层&#xff1a;实现poll函数 四、信号驱动 4.1 应用层&#xff1a;信号注册fcntl 4.2 驱动层&#xff1a;实现fasync函数 一、…...

看见统计——第三章 概率分布

看见统计——第三章 概率分布 参考 https://github.com/seeingtheory/Seeing-Theory中心极限定理 概率分布描述了随机变量取值的规律。 随机变量Random Variables &#x1f525; 定义&#xff1a;将样本空间中的结果映射到实数的函数 XXX 称为随机变量(random variable)&a…...

【基于众包标注的语文教材句子难易度评估研究 论文精读】

基于众包标注的语文教材句子难易度评估研究 论文精读信息摘 要0 引言1 相关研究2 众包标注方法3 语料库构建3.1 数据收集3.1 基于五点量表的专家标注3.3 基于成对比较的众包标注4 特征及模型4.1 特征抽取4.2 模型与实验设计4.2.1 任务一:单句绝对难度评估4.2.2 任务二:句对相对…...

实例五:MATLAB APP design-APP登录界面的设计

一、APP 界面设计展示 注:在账号和密码提示框输入相应的账号和密码后,点击登录按钮,即可跳转到程序中设计的工作界面。 二、APP设计界面运行结果展示...

作用域和闭包:

1、LHS和RHS查询编译一段代码&#xff0c;需要js引擎和编译器&#xff08;js引擎负责整个程序运行时所需的各种资源的调度&#xff0c;编译器只是js引擎的一部分&#xff0c;负责将JavaScript源码编译成机器能识别的机器指令&#xff0c;然后交给引擎运行&#xff09;编译的过程…...

Vue常见面试题?

1、说说你对SPA单页面的理解&#xff0c;它的优缺点是什么&#xff1f; SPA(single-page application)仅在Web页面初始化时加载相应的HTML、JavaScript和CSS。一旦页面加载完成&#xff0c;SPA不会因为用户的操作而进行页面的重新加载或跳转&#xff1b;取而代之的是利用路由机…...

前端借助Canvas实现压缩图片两种方法

一、具体代码 1、利用canvas压缩图片方法一 // 第一种压缩图片方法&#xff08;图片base64,图片类型,压缩比例,回调函数&#xff09;// 图片类型是指 image/png、image/jpeg、image/webp(仅Chrome支持)// 该方法对以上三种图片类型都适用 压缩结果的图片base64与原类型相同// …...

2023年美赛C题Wordle预测问题二建模及Python代码详细讲解

更新时间&#xff1a;2023-2-19 相关链接 &#xff08;1&#xff09;2023年美赛C题Wordle预测问题一建模及Python代码详细讲解 &#xff08;2&#xff09;2023年美赛C题Wordle预测问题二建模及Python代码详细讲解 &#xff08;3&#xff09;2023年美赛C题Wordle预测问题三、四…...

【算法】双指针

作者&#xff1a;指针不指南吗 专栏&#xff1a;算法篇 &#x1f43e;或许会很慢&#xff0c;但是不可以停下来&#x1f43e; 文章目录1.双指针分类2.双指针思想3.双指针应用1.双指针分类 常见问题分类 (1) 对于一个序列&#xff0c;用两个指针维护一段区间, 比如快速排序。 …...

Flutter-Widget-学习笔记

Widget 是整个视图描述的基础。 参考&#xff1a;https://docs.flutter.dev/resources/architectural-overview Widget 到底是什么呢&#xff1f; Widget 是 Flutter 功能的抽象描述&#xff0c;是视图的配置信息&#xff0c;同样也是数据的映射&#xff0c;是 Flutter 开发框…...

easyExcel 写复杂表头

写模板 模板图片&#xff1a; 实体类&#xff08;这里没有用Data 是因为Lombok和easyExcal的版本冲突&#xff0c;在导入读取的时候获取不到值&#xff09; package cn.iocoder.yudao.module.project.controller.admin.goods.vo;import com.alibaba.excel.annotation.ExcelI…...

关于线程池的执行流程和拒绝策略

使用线程池的好处为&#xff1a; 降低资源消耗&#xff1a;减少线程的创建和销毁带来的性能开销。 提高响应速度&#xff1a;当任务来时可以直接使用&#xff0c;不用等待线程创建 可管理性&#xff1a; 进行统一的分配&#xff0c;监控&#xff0c;避免大量的线程间因互相抢…...

【李忍考研传】二、约定

因为收学生证用了好些时间&#xff0c;李忍把学生证都交给班长后&#xff0c;就赶忙跑去食堂。远远地&#xff0c;他就看到那个瘦小的身影立在食堂正门前&#xff0c;那是他们约定每天午餐集合的地方。 “你咋这么慢啊……” “害&#xff01;帮班长收东西耽误了点时间&#…...

2023-2-19 刷题情况

修改两个元素的最小分数 题目描述 给你一个下标从 0 开始的整数数组 nums 。 nums 的 最小 得分是满足 0 < i < j < nums.length 的 |nums[i] - nums[j]| 的最小值。nums的 最大 得分是满足 0 < i < j < nums.length 的 |nums[i] - nums[j]| 的最大值。nu…...

行列式的性质

1 行列式使用如下性质定义 1&#xff09;单位矩阵行列式值为 1&#xff0c; &#xff0c;对于任意单位矩阵均成立&#xff1b; 2&#xff09;当矩阵交换一行后&#xff0c;行列式值改变符号&#xff0c;如置换矩阵的行列式值为 &#xff08;根据行交换次数决定&#xff09;&…...

12分钟讲解主流React库

本内容是对 Every React Library Explained in 12 Minutes 内容的翻译与整理。 React Router React Router 是一个用于控制网站导航的库&#xff0c;同时也允许你自定义网站的 URL。它使用自定义组件&#xff0c;如 BrowserRouter、Routes 和 Route 组件&#xff0c;以创建 UR…...

FPGA 的硬件结构

FPGA 的基本结构分为5 部分&#xff1a;可编程逻辑块&#xff08;CLB&#xff09;、输入/输出块&#xff08;IOB&#xff09;、逻辑块之间的布线资源、内嵌RAM 和内嵌的功能单元。 &#xff08;1&#xff09;可编程逻辑块&#xff08;CLB&#xff09; 一个基本的可编程逻辑块由…...

跨多个微服务使用 Redis 共享数据时,如何管理数据一致性?

在跨多个微服务使用 Redis 共享数据时&#xff0c;管理数据一致性是一个复杂但至关重要的问题。Redis 本身提供的原子操作和一些数据结构可以提供帮助&#xff0c;但大部分一致性保障需要应用层面的设计和策略。 首先要明确一点&#xff1a;在分布式系统中&#xff0c;强一致性…...

面试题:Java多线程并发

继承 Thread 类 Thread 类本质上是实现了 Runnable 接口的一个实例&#xff0c;代表一个线程的实例。启动线程的唯一方法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法&#xff0c;它将启动一个新线程&#xff0c;并执行 run()方法。 public class M…...

006网上订餐系统技术解析:打造高效便捷的餐饮服务平台

网上订餐系统技术解析&#xff1a;打造高效便捷的餐饮服务平台 在数字化生活方式普及的当下&#xff0c;网上订餐系统成为连接餐饮商家与消费者的重要桥梁。该系统以菜品分类、订单管理等模块为核心&#xff0c;通过前台展示与后台录入的分工协作&#xff0c;为管理员和会员提…...

【Python Cookbook】文件与 IO(二)

文件与 IO&#xff08;二&#xff09; 6.字符串的 I/O 操作7.读写压缩文件8.固定大小记录的文件迭代&#xff08;⭐⭐&#xff09; 6.字符串的 I/O 操作 你想使用操作类文件对象的程序来操作文本或二进制字符串。 使用 io.StringIO() 和 io.BytesIO() 类来创建类文件对象操作…...

[蓝桥杯]取球博弈

取球博弈 题目描述 两个人玩取球的游戏。 一共有 NN 个球&#xff0c;每人轮流取球&#xff0c;每次可取集合 n1,n2,n3n1​,n2​,n3​中的任何一个数目。 如果无法继续取球&#xff0c;则游戏结束。 此时&#xff0c;持有奇数个球的一方获胜。 如果两人都是奇数&#xff…...

macOS 上使用 Homebrew 安装redis-cli

在 macOS 上使用 Homebrew 安装 redis-cli&#xff08;Redis 命令行工具&#xff09;非常简单&#xff0c;以下是详细步骤&#xff1a; 1. 安装 Redis&#xff08;包含 redis-cli&#xff09; 运行以下命令安装 Redis&#xff1a; brew install redis这会安装完整的 Redis 服…...

[5-02-04].第01节:Jmeter环境搭建:

JMeter笔记大纲 Jmeter依赖于JDK&#xff0c;所以必须确保当前计算机上已经安装了JDK&#xff0c;并且配置了环境变量 一、JMeter概述&#xff1a; 1.1.JMeter是什么&#xff1a; JMeter是Appache组织使用java开发的一款测试工具 可以用于对服务器、网络或对象模拟巨大的负载…...