[Linux] Linux 进程程序替换

news2025/1/12 16:17:45

标题:[Linux] Linux 进程程序替换

个人主页@水墨不写bug

(图片来源于网络)

目录

O、前言

一、进程程序替换的直观现象(什么是进程程序替换?)

二、进程程序替换的原理

三、进程程序替换的函数(怎么使用进程程序替换?)

1.execl

2.execlp

3.execle

1.execv

2.execvp

3.execve

四、进程程序替换的实际应用场景(程序替换的意义?)

进程替换的常见场景:


 正文开始:

O、前言

        在之前,我们已经学习了什么是进程的创建,退出,等待,以及有关进程地址空间的问题。接下来的进程程序替换依然是属于进程控制的范畴,但是在实际应用中,是非常重要的一种技术。

        本文不直接像书本上一样,一开始就说一大堆概念,让人摸不清头脑,而是现观察进程程序替换的现象,然后再从现象中在进一步了解进程程序替换。

一、进程程序替换的直观现象(什么是进程程序替换?)

         进程程序替换有一些专门(对口)的函数,我们可以通过man手册查到其中的一个函数:

        接下来我们直接看一段代码,用一用这个函数:

#include<stdio.h>
#include<unistd.h>

int main()
{
    printf("process begin...\n");

    execl("/usr/bin/ls","ls","-a","-l",NULL);

    printf("process end...\n");

    return 0;
}

         两个打印语句分别标识进程开始与结束,话不多说,直接开始运行,结果如下:

        我们惊奇的发现,执行的现象与使用ls的现象差不多!

        通过进一步观察,可以发现:

        1)在调用execl函数之前的代码(打印process begin 的语句)执行了;

        2)调用execl函数就好像使用了 “ls” 命令;

        3)调用execl函数之后的代码没有被执行。

        为什么会发生这样的情况呢?别急,这就需要深入了解调用execl函数这一动作背后到底发生了什么——于是,我们需要谈一谈进程替换的原理。

二、进程程序替换的原理

        我们知道,我们写好并编译好的文件是一个 独立的 可执行程序:

        包括我们自己写的mytest,或者是系统上已经装好的ls等指令,都是一个独立的可执行程序。  

         execl 这类函数的功能就是,把一个新的独立的可执行程序覆盖式的加载到原来的运行起来的进程中,从而实现程序替换。

        一个进程,包括内核数据结构 + 代码和数据;这里的程序替换,替换的不仅仅是数据,还要替换代码!这也就意味着原来的代码和数据就被覆盖了,于是进程会从执行execl函数这一行开始,直接执行新加载的代码和数据。原来的数据自然就丢失了:这也就解释了 执行 execl 就像执行力 ls指令 ,在最后执行结束之后并没有打印 “process end” 的原因:

        1)执行execl之后,ls的代码和数据被加载的内存中,覆盖替换了原来的代码和数据;

        2)原来的 打印   “process end” 的代码由于被覆盖而丢失,所以没有执行;

        3)最终的返回值是ls指令的返回值,而不再是原来被覆盖的进程的返回值。


三、进程程序替换的函数(怎么使用进程程序替换?)

        我们可以通过进程程序替换的函数名称来略知一二,但是在那样通过函数名称来快速记忆之前,我们还是需要先一个一个了解进程程序替换的函数们:

list(初始化列类型):

1.execl

         就像我们之前演示的那样,其实就是execl函数使用方法,接下来需要对这个函数的传参细节做一些深入理解:

参数列表:

        *pathname: 需要替换的可执行程序的位置,需要指明具体的位置,既可以使用绝对路径,也可以使用相对路径。

        (比如想要替换ls命令,ls命令本质是一个可执行程序,位于/usr/bin/ls,于是我们第一个参数需要这样传递:“/usr/bin/ls”)

        *arg: 需要替换的可执行程序的名称

        (需要替换的ls命令的名称就是ls,于是需要传递:“ls”)

         ... : 参数列表

        (类似于printf的参数列表不限制打印的参数的个数一样,我们在命令行上想要使用不同的命令,传递的参数的个数是不同的,于是通过参数列表,我们可以传递不同的参数个数,来达到正确执行不同指令的目的)

        比如下面的这一个实例就很好的体现了上述的规则:

实例一:

 makefile:        

        当我们想要一次生成多个目标文件,那么可以定义一个伪目标:all 

        在伪目标后面 + “ : ”+ “ 需要的依赖文件名称 ” 

        在下文表明生成依赖文件的依赖方法即可:

.PHONY:all
all:mytest mmtest

mmtest:mytest.cc
	g++ -o $@ $^
mytest:pra_exec.c
	gcc -o $@ $^

.PHONY:clean
clean:
	rm -r mytest mmtest

pra_exec.c:

#include<stdio.h>
#include<unistd.h>

int main()
{
    printf("process begin...\n");
    execl("/usr/bin/ls","ls","-a","-l",NULL);
    printf("process end...\n");

    return 0;
}

mytest.cc

#include<iostream>
#include<unistd.h>
using namespace std;

int main()
{
    cout<<"C++进程开始运行"<<endl;
    execl("./mytest","./mytest",NULL);
    cout<<"C++进程结束运行"<<endl;

    return 0;
}

        由于我们已经编写了makefile,所以只需要make,就可以生成两个可执行程序。

        运行结果:

        在进程运行的过程中,我们发现进行了两次进程程序替换:

        ./mmytest (C++程序) ---> ./mytest(C程序) ---> /usr/bin/ls (系统命令C程序)

我们可以通过观察打印信息来观察。

        到这里我们可以得出结论:

                execl可以替换任何语言的可执行程序。(包括java,python,shell脚本语言等),唯一不同的是通过execl调用的时候传递的参数不同。

接下来的介绍只给出具体函数的使用实例,不再重复介绍同样性质的参数。 

2.execlp

#include <unistd.h>
int main()
{
    // 带p的,可以使用环境变量PATH,无需写全路径
    execlp("ps", "ps", "-ef", NULL);
    
    exit(0);
}

3.execle

#include <unistd.h>
int main()
{
    char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
    
    // 带e的,需要自己组装环境变量
    execle("ps", "ps", "-ef", NULL, envp);
   
    exit(0);
}

vector(数组类型):

1.execv

#include <unistd.h>
int main()
{
    char *const argv[] = {"ps", "-ef", NULL};
    //带v的需要传入数组形式的参数列表 
    execv("/bin/ps", argv);
     
    exit(0);
}

2.execvp

#include <unistd.h>
int main()
{
    char *const argv[] = {"ps", "-ef", NULL};
    
    // 带p的,可以使用环境变量PATH,无需写全路径
    execvp("ps", argv);
    
    exit(0);
}

3.execve

#include <unistd.h>
int main()
{
    char *const argv[] = {"ps", "-ef", NULL};
    char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
    
    // 带e的,需要自己组装环境变量
    execve("/bin/ps", argv, envp);
    exit(0);
}

函数解释

        这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。

        如果调用出错则返回-1

        所以exec函数只有出错的返回值而没有成功的返回值。

命名理解

这些函数原型看起来很容易混,但只要掌握了规律就很好记。

l(list) : 表示参数采用列表

v(vector) : 参数用数组

p(path) : 有p自动搜索环境变量PATH

e(env) : 表示自己维护环境变量

 exec*函数簇函数之间的关系:

        本质上,这些exec*函数都是对execve函数的封装,为什么?

        因为execve是一个系统调用函数!!本质上底层调用的都是相同的形式调用的execve,只不过是上层的封装转换的参数传递的方式。


四、进程程序替换的实际应用场景(程序替换的意义?)

        在我们的项目中,我们的父进程一直是运行的,不能说父进程执行了想要执行ls命令,在执行了之后自己却退出了。所以,我们在一般情况下,一定不能让父进程发生程序替换,不然父进程的代码和数据被子进程替换之后,代码和数据就丢失了!        

         所以我们需要fork创建子进程,让子进程来代替父进程来执行exec*这一类的函数,让子进程来发生程序替换,让子进程的代码和数据被替换掉,这样父进程就可以保留!

进程替换的常见场景:

        用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。

        当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。

        调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。


完~

未经作者同意禁止转载 

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

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

相关文章

软件游戏d3dx9_43.dll丢失怎么解决,总结6个解决方法

d3dx9_43.dll是DirectX 9组件的一部分&#xff0c;这是一个由微软开发的图形API&#xff0c;用于处理与游戏和多媒体相关的图形渲染。d3dx9_43.dll库包含了DirectX 9中用于3D图形渲染和处理的许多实用程序函数。这些函数为开发者提供了创建复杂3D模型、纹理映射、光影效果以及各…

涂鸦革新WebRTC技术!让IPC监测低延时、高可靠更安全

随着科技的飞速发展&#xff0c;越来越多人开始关注居家安全、食品安全、校园安全等领域&#xff0c;大家对实时监测的需求也在不断升级。想象一下&#xff0c;无论身处何地&#xff0c;只需轻触屏幕&#xff0c;就能实时查看家中、办公室或任何你关心的地方&#xff0c;这不再…

MySQL中表的操作

目录 一、查看所有表 1.1、语法 二、创建表 2.1、语法 2.2、示例&#xff1a; 2.3、创建数据加时使⽤校验语句[if not exists] 三、查看表结构 3.1、语法 3.2、示例 四、删除表 4.1、语法 4.2、示例 4.3、注意事项 五、主要数据类型 5.1、数值类型 5.2、日期和…

揭秘语音识别巨头1:国内外顶尖技术服务商全解析01(万字长文)

一、学习导航 解密语音识别巨头&#xff1a;国内顶尖技术服务商全解析00&#xff1a;学习地图 解密语音识别巨头&#xff1a;国内顶尖技术服务商全解析01&#xff1a;微软语音&#xff0c;商业No.1 解密语音识别巨头&#xff1a;国内顶尖技术服务商全解析02&#xff1a;百度…

ProxyPin 抓包,原来可以这么简单!

你是否还在为网络请求的抓包发愁&#xff1f;其实&#xff0c;ProxyPin 可以让抓包操作变得异常简单&#xff01;不需要复杂的设置&#xff0c;也不用繁琐的配置&#xff0c;轻松几步就能实现。让我们一起来看看吧&#xff01; 抓包操作常用于测试网络请求、分析接口响应&#…

Javascript剩余参数、arguments对象和柯里化函数

在JavaScript中&#xff0c;函数的剩余参数&#xff08;Rest Parameters&#xff09;和arguments对象都是用于处理函数接收的不定数量参数的机制。虽然它们的功能相似&#xff0c;但使用方式和适用场景有所不同。下面详细解释这两个概念。 剩余参数&#xff08;Rest Parameter…

手撕数据结构 —— 栈(C语言讲解)

目录 1.认识栈 什么是栈 栈的示意图 2.如何实现栈 3.栈的实现 Stack.h中接口总览 具体实现 结构的定义 初始化栈 销毁栈 入栈 出栈 取栈顶元素 获取有效元素的个数 判断栈是否为空 4.完整代码附录 Stack.h Stack.c 1.认识栈 什么是栈 栈是一种特殊的线性表…

【动物识别系统】Python+卷积神经网络算法+人工智能+深度学习+机器学习+计算机课设项目+Django网页界面

一、介绍 动物识别系统。本项目以Python作为主要编程语言&#xff0c;并基于TensorFlow搭建ResNet50卷积神经网络算法模型&#xff0c;通过收集4种常见的动物图像数据集&#xff08;猫、狗、鸡、马&#xff09;然后进行模型训练&#xff0c;得到一个识别精度较高的模型文件&am…

DS线性表之单链表的讲解和实现(2)

文章目录 前言一、链表的概念二、链表的分类三、链表的结构四、前置知识准备五、单链表的模拟实现定义头节点初始化单链表销毁单链表打印单链表申请节点头插数据尾插数据头删数据尾删数据查询数据在pos位置之后插入数据删除pos位置之后的数据 总结 前言 本篇的单链表完全来说是…

使用PyTorch从0实现Fashion-MNIST数据集分类

完整代码&#xff1a; from d2l import torch as d2l import torch from torchvision import transforms from torchvision import datasets from torch.utils.data import DataLoader import matplotlib.pyplot as plt from IPython import displaydef get_fashion_mnist_la…

BBR 的不公平性

BBR 公平收敛在相图中的细节 和 aimd&#xff0c;bbr&#xff0c;inflt 守恒的收敛相图总结 已经介绍了 BBR 的 gain 不公平性&#xff0c;本文介绍 BBR 的 RTT 不公平性。 直觉上&#xff0c;BBR 采用 probe_quota gain * maxbw * minrtt 来 probe 带宽&#xff0c;minrtt 越…

掌握Postman,开启API测试新纪元!

Postman是一款流行的API测试工具和开发环境&#xff0c;旨在简化API开发过程、测试和文档编制。它提供了一套功能强大的工具&#xff0c;帮助开发人员更轻松地构建、测试和调试Web服务。 Postman 工具的优势 Postman 可以快速构建请求、还可以保存以后再使用。 Postman 还提…

改进系列:TransUnet结合SAM box改进对MICCAI FLARE腹部13器官图像分割

目录 1、前言 2、实现思路 3、实验代码 3.1 环境配置 3.2 数据集 3.3 训练 3.4 指标 3.5 推理 4、其他 1、前言 本章尝试将TransUnet和SAM结合&#xff0c;以期望达到更换的模型 TransUnet作为医学图像分割的基准&#xff0c;在许多数据集上均取得了很好的效果&#x…

JavaSE——认识异常

1.概念 在生活中&#xff0c;人有时会生病&#xff0c;在程序中也是一样&#xff0c;程序猿是一帮办事严谨、追求完美的高科技人才。在日常开发中&#xff0c;绞尽脑汁将代码写的尽善尽美&#xff0c;在程序运行过程中&#xff0c;难免会出现一些奇奇怪怪的问题。有时通过代码很…

2024/10/12 计组大题专训

2018&#xff1a; 2019&#xff1a; 2020&#xff1a; 2021&#xff1a;

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表&#xff08;重点掌握&#xff09;】 可以使用类&#xff1a;“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁&#xff0c;就是直接给put&#xff0c;get等方法加上synch…

AI+若依框架day02

项目实战 项目介绍 帝可得是什么 角色和功能 页面原型 库表设计 初始AI AIGC 提示工程 Prompt的组成 Prompt练习 项目搭建 点位管理 需求说明 库表设计

多线程学习篇四:synchronized

1. synchronized 的使用 1.1 作用于实例方法 Slf4j(topic "c.Test01") public class Test01 {public synchronized void method1() {// 代码逻辑} } 等价于下列写法&#xff1a; Slf4j(topic "c.Test01") public class Test01 {public void method1…

基于机器学习的虚假新闻智能检测系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 随着互联网的普及和社交媒体的发展&#xff0c;虚假新闻&#xff08;fake news&#xff09;问题日益严重&#xff0c;对社会和个人产生了诸多负面影响。传统的新闻审核方法通常依赖于人工审核&…

基于gewechat制作第一个微信聊天机器人

Gewe 个微框架 GeWe&#xff08;个微框架&#xff09;是一个创新性的软件开发框架&#xff0c;为个人微信号以及企业信息安全提供了强大的功能和保障。GeWe的设计旨在简化开发过程&#xff0c;使开发者能够高效、灵活地构建和定制通信协议&#xff0c;以满足不同应用场景的需求…