【Linux】进程替换

news2024/9/24 13:22:23

文章目录

      • 进程程序替换
      • 替换原理
      • 替换函数
      • 函数返回值
      • 函数命名理解
          • 在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 myexe

myload:myload.c
	gcc -0 $@ $^ -std=c99
myexe:myexe.c
    gcc -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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【原创】java+swing+sqlserver药品管理系统设计与实现

之前数据库都是用的mysql&#xff0c;今天我们使用sqlserver在配合swing来开发一个药品管理系统。方便医院工作人员进行药品的管理&#xff0c;基础功能基本都是一些增删改查操作。 功能分析&#xff1a; 药品管理系统主要提供给管理员和员工使用&#xff0c;功能如下&#x…

[python]win10安装gym

anconda3里面安装&#xff1a; pip install gym[atari,accept-rom-license]0.26.1 AutoRom 测试结果&#xff1a; import gym envgym.make(Assault-v4,render_modehuman) env.reset() for _ in range(100000): actionenv.action_space.sample() env.step(action) env.c…

数据结构——算法的时间复杂度

&#x1f307;个人主页&#xff1a;_麦麦_ &#x1f4da;今日名言&#xff1a;生命中曾经有过的所有灿烂&#xff0c;都终究需要用寂寞来偿还。——《百年孤独》 目录 一、前言 二、正文 1.算法效率 1.1如何衡量一个算法的好坏 1.2算法的复杂度 2. 时间复杂度 2.1时间复杂度的…

元胞自动机

文章目录前言文献阅读摘要主要贡献方法框架实验结论元胞自动机元胞自动机是什么&#xff1f;构成及规则案例及代码实现总结前言 This week,the paper proposes a Multi-directional Temporal Convolutional Artificial Neural Network (MTCAN) model to impute and forecast P…

部署dapr的辛酸历程

前言dapr大概的了解&#xff0c;个人理解他就是一个分布式服务的管理&#xff0c;把微服务常用的组件(缓存&#xff0c;消息中间件、分布式锁、安全id4等)和监控以及服务注册、发现等等一系列功能以一个很抽象的方式管理起来。可能我们部署微服务用consul、ocelot、polly套件、…

DDD单根 聚合根 实体 值对象

前言2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity in the Heart of Software &#xff08;领域驱动设计&#xff09;&#xff0c;简称Evans DDD。快二十年的时间&#xff0c;领域驱动设计在不断地发展&#xff0c;后微服务时代强调的东西&#xff0c;在国…

Nginx网站服务及优化

Nginx网站服务及优化一、简介1、Nginx概述2、Nginx和Apache的优缺点比较3、Nginx和Apache最核心的区别二、Linux中的I/O三、Nginx编译安装详细1、关闭防火墙、安装依赖关系2、新建用户nginx便于管理3、将压缩包传入到/opt目录下&#xff0c;编译安装4、做软连接并启动nginx5、创…

软件测试简历个人技能和项目经验怎么写?(附项目资料)

目录 前言 个人技能 项目实战经验 项目名称&#xff1a;苏州银行项目&#xff08;webapp&#xff09; 项目描述&#xff1a; 项目名称&#xff1a;中国平安项目&#xff08;webapp&#xff09; 项目描述&#xff1a; 项目名称&#xff1a;苏宁易购项目&#xff08;webapp&a…

软件体系结构(期末复习)

文章目录软件体系结构软件体系结构概论软件体系结构建模软件体系结构风格统一建模语言基于体系结构的软件开发软件体系结构 软件体系结构概论 软件危机是指计算机软件的开发和维护过程中遇到的一系列严重问题。 软件危机的表现: 软件危机的原因: 软件工程的基本要素&#xf…

轻松上手nacos使用

三步上手nacos使用1.为什么使用nacos?2.如何使用nacos1.为什么使用nacos? 1.服务发现中心。 微服务将自身注册至 Nacos&#xff0c;网关从 Nacos 获取微服务列表。 2.配置中心。 微服务众多&#xff0c;它们的配置信息也非常复杂&#xff0c;为了提高系统的可维护性&#xf…

每天一个linux命令---awk

awk命令 1. 简介 awk是一种处理文本文件的语言&#xff0c;是一个强大的文本分析工具&#xff0c;grep、sed、awk并称为shell中文本处理的三剑客。 AWK 是一种处理文本文件的语言&#xff0c;是一个强大的文本分析工具。 之所以叫 AWK 是因为其取了三位创始人 Alfred Aho&am…

1.OCR--文本检测算法FCENet

文章目录1.简介2.主要工作2.1 傅里叶轮廓嵌入(Fourier Contour Embedding)2.2 FCE模型3.代码实现参考资料欢迎访问个人网络日志&#x1f339;&#x1f339;知行空间&#x1f339;&#x1f339; 论文:Fourier Contour Embedding for Arbitrary-Shaped Text Detection 1.简介 这…

设计模式之中介模式与解释器模式详解和应用

目录1 中介模式详解1.1 中介模式的定义1.1.1 中介者模式在生活场景中应用1.1.2 中介者模式的使用场景1.2 中介模式的通用实现1.2.1 类图设计1.2.2 代码实现1.3 中介模式应用案例之聊天室1.3.1 类图设计1.3.2 代码实现1.4 中介者模式在源码中应用1.4.1 jdk中Timer类1.5 中介者模…

logd守护进程

logd守护进程1、adb logcat命令2、logd守护进程启动2.1 logd文件目录2.2 main方法启动3、LogBuffer缓存大小3.1 缓存大小优先级设置3.2 缓存大小相关代码位置android12-release1、adb logcat命令 命令功能adb bugreport > bugreport.txtbugreport 日志adb shell dmesg >…

kafka-11-kafka的监控工具和常用配置参数

kafka官方文档 参考Kafka三款监控工具比较 1 查看kafka的版本 进入kafka所在目录&#xff0c;通过查看libs目录下的jar包。 2.11是scala的版本&#xff0c;2.0.0是kafka的版本。 测试环境 #systemctl start zookeeper #systemctl start kafkka 2 kafka的常用配置 Kafka使用…

SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】

SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】 目录SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】一、创建一个SpringBoot项目二、修改pom.xml中SpringBoot的版本三、配置文件3.1 application-dev.ym…

2.TCP/UDP什么时候选择,HTTP,使用TCP/UDP的协议有哪些,TCP三次握手四次挥手大概流程,为什么要三次握手.

文章目录1.什么时候选择 TCP,什么时候选 UDP?2. HTTP 基于 TCP 还是 UDP&#xff1f;3.使用 TCP 的协议有哪些?使用 UDP 的协议有哪些?4.TCP 三次握手和四次挥手&#xff08;非常重要、传输层&#xff09;5.为什么要三次握手?1.什么时候选择 TCP,什么时候选 UDP? UDP 一般…

Spring Cloud Nacos实战(五)- 命名空间分组和DataID三者关系

Nacos命名空间分组和DataID三者关系 名词解释 命名空间&#xff08;Namespace&#xff09; ​ 用于进行租户粒度的配置隔离。不同的命名空间下&#xff0c;可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离&#xff0c;例如开发…

Kubernetes一 Kubernetes之入门

二 Kubernetes介绍 1.1 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个时代&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点&#xff1a;不能为应…

机器学习实战教程(六):决策树

决策树 决策树是什么&#xff1f;决策树(decision tree)是一种基本的分类与回归方法。举个通俗易懂的例子&#xff0c;如下图所示的流程图就是一个决策树&#xff0c;长方形代表判断模块(decision block)&#xff0c;椭圆形成代表终止模块(terminating block)&#xff0c;表示…