Linux|进程程序替换

news2025/2/23 4:14:14

目录

什么是进程替换

替换原理

exec函数

exec* 函数的共性


什么是进程替换

          进程程序替换是指将一个进程中正在运行的程序替换为另一个全新的程序的过程,但替换不是创建新进程,只是将对应程序的代码和数据进行替换。具体来说,这个替换过程涉及将磁盘中的新程序加载到内存结构中,并重新建立页表映射,然后更新一系列的组件,使得执行程序替换的进程(如子进程)与新程序关联起来。这样,该进程就不再执行原来的程序,而是开始执行新的程序。

          试想我们创建一个进程的时候是先创建pcb,地址空间,页表等,还是先把程序加载到内存。答案是前者,而程序替换就是不再创建pcb,本质工作就是加载!!!

        进程替换的使用在很多情况下都是使用子进程来完成。当我们想让一个子进程执行与父进程不同的代码片段时,就可以通过进程程序替换来实现,这时父进程完成自己的程序,子进程进行替换。这里需说明一下,子进程的进程替换不会影响父进程,因为进程具有独立性。当刚开始创建子进程时,子进程内部的指针指向父进程的数据和代码,子进程一旦发生替换时(改动了原本的数据),要替换的部分将会进行写时拷贝,开辟一块空间。

          简而言之,进程程序替换就是在运行自己程序的时候可以替换成其他我想执行的程序,在进程程序替换后,我原来的程序就不存在了,进程中就只有我替换的程序了。

替换原理

          一般来说用fork创建子进程去执行我想替换的程序,fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支)。想要完成程序的替换也就是进程属性的修改,这是操作系统内核才有的权限,必须要由操作系统来完成,所以我们必须要使用对应的系统调用。进程程序替换往往要调用一种exec函数以执行另一个程序,当进程调替换时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。这里注重强调一下,调用exec进行进程替换并不创建新进程,替换的本质就是加载,将磁盘上的数据和代码加载到内存中,从而更新一系列数据重新建立起关系,所以调用exec前后该进程的 id 并未改变。

         

exec函数

此函数共有六种以exec开头的函数,统称exec函数:

头文件:

#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[]);

exec* 函数的共性

1,程序一旦被 exec* 替换成功,exec* 后续的代码不在执行,因为此时的进程被替换掉了。若替换失败,此进程后面的代码才继续执行。

2,exec* 只有失败返回值-1,没有成功返回值,因为一旦成功此进程将被替换。

3,替换完成,不会创建新的进程,即PCB结构。

exec* 的各种类型函数中,虽说各有各的不同,但是这里只要明白里面的各种参数功能,就能够理解exec* 函数是如何进行替换的。

        下面的演示为了方便,这里替换的进程统一用Linux系统下的指令。这里先说明一下,在Linux中,指令本质上是程序,各种命令实际上都是可执行程序。当进程执行时,它会加载程序到内存中,并通过虚拟地址空间与物理内存之间的映射关系来执行这些指令。

形式一:

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

path: 要替换程序的路径。

arg:表示要替换的进程程序,这里参数可以有多个,用于指定程序的输入、选项或其他必要的信息,但最后必须以NULL结尾,以标记参数列表结束。

例:execl("/usr/bin/ls", "ls", "-l", "-a", NULL);    将此时进程替换成在路径 "/usr/bin/ls" 下的 ls -l -a 进程,若在此路径下不存在指定的进程,则替换失败,如:execl("/usr/bin/l", "ls", "-l", "-a", NULL);  没有此路径,替换失败。

形式二:

int execlp(const char* file, const char* arg, ...);

file:这是你要执行的程序的名称(即可执行文件名)。如果 file 中不包含路径信息(即只是程序名而不是完整的路径),则会在 PATH 环境变量中定义的目录列表中查找该程序。

arg:与execl中的arg一样,表示要替换的进程程序。

例:execlp("ls", "ls", "-a", "-l", NULL);      将此时进程替换成 ls -a -l 进程。注意,这里的两个参数 "ls" 不重复,各自表示的含义不一样。

        在exec*的各种形式函数中,后面带 p 表示 PATH 环境变量,这时只用传达进程名称即可,不用告诉系统程序在哪里,系统在替换时会自动去PATH环境变量中查找。

形式三:

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

argv[]:用指针数组argv来表示替换的进程程序。

例:char* argv = { "ls", "-a", "-l" };   execv("/usr/bin/ls", argv);   效果与上相同。

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

例:char* argv = { "ls", "-a", "-l" };    execvp("ls", argv);   效果类同

         在exec*的各种形式函数中,后面带 v 的表示使用指针数组的形式表示要进行替换的进程程序。后面带 l 的表示以参数列表的形式表示要进行替换的进程程序。

形式四:

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

envp[]自定义存储环境变量的指针数组envp[],将此进程自定义的环境变量表覆盖替换程序的环境变量表。

        exec* 函数后面带 e 的表示环境变量。至于为什么引入此种功能我们先来了解当替换我们自己写的程序时的情况,这里以execl函数为例。说明一下,程序替换可替换在此系统下的所有高级语言程序,即包括python、C/C++、java等。因为所有的语言运行之后都是进程这里以C/C++为例

code.cpp文件:

#include <iostream>

#include <cstdio>

using namespace std;

int main(int argc, char* argv[], char* env[])

{

    for (int i = 0; argv[i]; i++)

    {

        fprintf(stdout, "argv[%d]: %s\n", i, argv[i]);

        fprintf(stdout, "env[%d]: %s\n", i, env[i]);  //运行此时的环境变量

    }

    cout << "code2.exe option" << endl;

    return 0;

}

run.cpp文件:

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <sys/types.h>

#include <sys/wait.h>

#include <unistd.h>

using namespace std;

int main()

{

    pid_t id  = fork();

    if (id == 0) // 子进程进行进程替换

    {

        cout << "I am a child process, pid = " << getpid() << endl;

        cout << "exec is begining" << endl;

        execl("./code.exe", "code.exe", "-a", "-b", NULL); // 运行自己的程序code.exe

        cout << "exec end" << endl; // execl之后的代码不会运行,因为此时进程被exec替换

    }

    //父进程执行自己的程序

    int w = wait(NULL);

    if (w > 0)

        cout << "wait success" << endl;

    else

        cout << "wait failure" << endl;

    return 0;

}

编译code.cpp为code.exe,run.cpp为run,运行run输出:

I am a child process, pid = 29117

exec is begining

argv[0]: code.exe

env[0]: XDG_SESSION_ID=6732

argv[1]: -a

env[1]: HOSTNAME=VM-16-10-centos

argv[2]: -b

env[2]: TERM=xterm

code.exe option

wait success         

          这里需要说明一下,进程在替换时是不会替换掉环境变量的数据,也就是说以上的程序run默认可以通过地址空间继承的方式,让子进程拿到环境变量数据,所以,当我们调用子进程可以输出整个系统的环境变量,因为所有进程都是shell的子进程。但是若是子进程或孙子进程新增环境变量,父进程的进程地址空间中是没有存储的,若父进程想使用子进程新增的环境变量,来执行其他程序,可以使用putenv来为子进程添加新的环境变量,但创建出来的环境变量不会影响前面的父进程,只会影响后面的替换来的程序,如果想新替换来的程序使用全新的环境变量,这时就需要使用 execl* 函数后面带 e 类型的接口。 exec* 后缀加上e的,表示需要传入环境变量表,此时将覆盖原本的环境变量数据。

可以看到我们成功调用了一个c++程序,并且传递使用了新的环境变量。

(最后再列出所有exec函数的联系与区别)

题外话:

查看进程语句:

while :; do ps ajx|head -1 && ps ajx |grep myprocess|grep -v grep;sleep 1;done

使用grep -v grep是为了排除grep自身的进程记录

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

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

相关文章

2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略(详细解题思路)

在当下&#xff0c; 日益发展的时代&#xff0c;宠物的数量应该均为稳步上升&#xff0c;在美国出现了下降的趋势&#xff0c; 中国 2019-2020 年也下降&#xff0c;这部分变化可能与疫情相关。需要对该部分进行必要的解释说明。 问题 1: 基于附件 1 中的数据及您的团队收集的…

人工智能(AI)与机器学习(ML)基础知识

目录 1. 人工智能与机器学习的核心概念 什么是人工智能&#xff08;AI&#xff09;&#xff1f; 什么是机器学习&#xff08;ML&#xff09;&#xff1f; 什么是深度学习&#xff08;DL&#xff09;&#xff1f; 2. 机器学习的三大类型 &#xff08;1&#xff09;监督式学…

【从零开始的LeetCode-算法】3233. 统计不是特殊数字的数字数量

给你两个 正整数 l 和 r。对于任何数字 x&#xff0c;x 的所有正因数&#xff08;除了 x 本身&#xff09;被称为 x 的 真因数。 如果一个数字恰好仅有两个 真因数&#xff0c;则称该数字为 特殊数字。例如&#xff1a; 数字 4 是 特殊数字&#xff0c;因为它的真因数为 1 和…

web——sqliabs靶场——第十二关——(基于错误的双引号 POST 型字符型变形的注入)

判断注入类型 a OR 1 1# 发现没有报错 &#xff0c;说明单引号不是闭合类型 测试别的注入条件 a) OR 1 1# a)) OR 1 1# a" OR 11 发现可以用双引号闭合 发现是")闭合 之后的流程还是与11关一样 爆破显示位 先抓包 是post传参&#xff0c;用hackbar来传参 unam…

IDEA 下载源码很慢,Download Source使用阿里云镜像仓库

参考&#xff1a; IDEA maven本地仓库、中心仓库、远程仓库配置 在观看第三方jar包的api时&#xff0c;有时候需要下载源码看下注释。 这个时候用idea 上的提示的Download Source会发现一直下载不下来。 因此就怀疑用的是apache的maven仓库&#xff0c;不是我们用的 aliyun 镜…

1+X应急响应(网络)病毒与木马的处置:

病毒与木马的处置&#xff1a; 病毒与木马的简介&#xff1a; 病毒和木马的排查与恢复&#xff1a;

2024年亚太地区数学建模大赛D题-探索量子加速人工智能的前沿领域

量子计算在解决复杂问题和处理大规模数据集方面具有巨大的潜力&#xff0c;远远超过了经典计算机的能力。当与人工智能&#xff08;AI&#xff09;集成时&#xff0c;量子计算可以带来革命性的突破。它的并行处理能力能够在更短的时间内解决更复杂的问题&#xff0c;这对优化和…

一个小的可编辑表格问题引起的思考

11.21工作中遇到的问题 预期&#xff1a;当每行获取红包金额的时候若出现错误&#xff0c;右侧当行会出现提示 结果&#xff1a;获取红包金额出现错误&#xff0c;右侧对应行并没有出现错误提示 我发现&#xff0c;当我们设置readonly的时候&#xff0c;其实render函数依旧是…

【Linux课程学习】:进程描述---PCB(Process Control Block)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux课程学习 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 1.基本概念&#xff1a; &#x1f95d;进程的…

java基础概念36:正则表达式1

一、正则表达式的作用 作用一&#xff1a;校验字符串是否满足规则&#xff1b;作用二&#xff1a;在一段文本中查找满足要求的内容。——爬虫 二、正则表达式 2-1、字符类 示例&#xff1a; public static void main(String[] args) {System.out.println("a".matc…

设计模式之 命令模式

命令模式&#xff08;Command Pattern&#xff09;是行为型设计模式之一&#xff0c;它将请求&#xff08;或命令&#xff09;封装成一个对象&#xff0c;从而使用户能够将请求发送者与请求接收者解耦。通过命令模式&#xff0c;调用操作的对象与执行操作的对象不直接关联&…

GRU (门控循环单元 - 基于RNN - 简化LSTM又快又好 - 体现注意力的思想) + 代码实现 —— 笔记3.5《动手学深度学习》

目录 0. 前言 1. 门控隐状态 1.1 重置门和更新门 1.2 候选隐状态 1.3 隐状态 2. 从零开始实现 2.1 初始化模型参数 2.2 定义模型 2.3 训练与预测 3 简洁实现 4. 小结 0. 前言 课程全部代码&#xff08;pytorch版&#xff09;已上传到附件看懂上一篇RNN的所有细节&am…

实践篇:青果IP助理跨境电商的高效采集

写在前面&#xff1a; 近年来&#xff0c;跨境电商行业迅速崛起&#xff0c;成为全球贸易的重要组成部分。据市场调研机构Statista数据显示&#xff0c;2024年全球跨境电商市场规模预计将突破5万亿美元&#xff0c;覆盖数十亿消费者。跨境电商的竞争日益激烈&#xff0c;商家不…

电子应用设计方案-16:智能闹钟系统方案设计

智能闹钟系统方案设计 一、系统概述 本智能闹钟系统旨在为用户提供更加个性化、智能化和便捷的闹钟服务&#xff0c;帮助用户更有效地管理时间和起床。 二、系统组成 1. 微控制器 - 选用低功耗、高性能的微控制器&#xff0c;如 STM32 系列&#xff0c;负责整个系统的控制和数据…

QML —— 3种等待指示控件(附源码)

效果如下 说明 BusyIndicator应用于指示在加载内容或UI被阻止等待资源可用时的活动。BusyIndicator类似于一个不确定的ProgressBar。两者都可以用来指示背景活动。主要区别在于视觉效果,ProgressBar还可以显示具体的进度(当可以确定时)。由于视觉差异,繁忙指示器和不确定的…

Leetcode448. 找到所有数组中消失的数字(HOT100)+Leetcode139. 单词拆分(HOT100)

链接 链接2 这两道题略微有点难&#xff0c;其中第一道题我自己解出来了&#xff0c;还补充了一个更好的解法&#xff0c;在空间上做了优化。 第二道题看了别人的题解&#xff0c;我正在努力理解。 题目一&#xff1a; 题意&#xff1a;为什么有n个元素&#xff0c;但是还有…

通过轻易云平台实现聚水潭数据高效集成到MySQL的技术方案

聚水潭数据集成到MySQL的技术案例分享 在本次技术案例中&#xff0c;我们将详细探讨如何通过轻易云数据集成平台&#xff0c;将聚水潭的数据高效、可靠地集成到MySQL数据库中。具体方案为“聚水谭-店铺查询单-->BI斯莱蒙-店铺表”。这一过程不仅需要处理大量数据的快速写入…

华为云容器监控平台

首先搜索CCE,点击云容器引擎CCE 有不同的测试&#xff0c;生产&#xff0c;正式环境 工作负载--直接查询服务名看监控 数据库都是走的一个 Redis的查看

机器学习系列----关联分析

目录 1. 关联分析的基本概念 1.1定义 1.2常用算法 2.Apriori 算法的实现 2.1 工作原理 2.2 算法步骤 2.3 优缺点 2.4 时间复杂度 2.5实际运用----市场购物篮分析 3. FP-Growth 算法 3.1 工作原理 3.2 算法步骤 3.3 优缺点 3.4 时间复杂度 3.5实际运用——网页点…

前端面试vue篇:Vue2 和 Vue3 在设计和性能上有显著区别

Vue3 相对于 Vue2 的主要改进和性能提升体现在以下几个关键领域 1.响应式系统&#xff1a; (1)Vue2 使用 Object.defineProperty 遍历对象的所有属性来实现响应式&#xff0c;这在大型应用中可能导致性能瓶颈&#xff0c;尤其是在组件初次渲染和大量数据变化时。 (2)Vue3 引入了…