[linux进程控制]进程替换

文章目录

  • 1.进程替换的概念和原理
  • 2.如何完成进程替换
    • 2.1exec系列函数
      • 加载器的底层系统调用接口
      • 基于execve的封装--库函数
    • 2.2 int execl(const char *path, const char *arg, ...);
      • 1.在当前进程进行替换
      • 2.在子进程进行替换
    • 2.3 int execv(const char *path, char *const argv[]);
    • 2.4 int execlp(const char *file, const char *arg, ...);
    • 2.5 int execvp(const char *file, char *const argv[]);
    • 2.6 int execle(const char *path, const char *arg, ..., char * const envp[]);
      • 1.Makefile: 一次生成多个可执行程序
      • 2.子进程中执行自己写的C/C++程序
        • 2.1自己写的C/C++程序
        • 2.2执行自己写的C/C++程序
      • 3.子进程中执行自己写的py/sh程序
      • 4. int execle(const char *path, const char *arg, ..., char * const envp[]);
        • 4.1自己写的C/C++程序
        • 4.2执行自己写的C/C++程序
    • 2.7 int execvpe(const char *file, char *const argv[], char *const envp[]);

1.进程替换的概念和原理

之前讲过fork()函数的用法:

  1. 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程不处理客户端请求,生成子
    进程来处理这个请求。
  2. 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。==>进程替换

fork()之后 父子进程各自执行父进程代码的一部分 如果子进程想执行一个另外的/全新的程序要怎么做呢?

本来父子进程共享代码和数据 (数据写时拷贝) 子进程怎么去拥有自己的代码呢?

进程替换完成这个功能: 通过特定的接口 把磁盘上一个全新的程序(代码和数据)加载到子进程的地址空间中

当进程替换后 都会发生什么呢?

  1. 新程序的代码和数据加载到内存
  2. 进程替换并没有创建新的进程 所以该进程的pid并不改变
  3. 原进程即被替换的进程的PCB/进程地址空间/页表没有释放 新程序的PCB/进程地址空间/页表没有被创建 而是将原进程的PCB/进程地址空间/页表的内容完全替换成新程序的PCB/进程地址空间/页表的内容 页表左侧替换成新程序对应的虚拟地址 页表右侧替换成新程序的物理地址
  4. 旧进程的用户空间代码和数据完全被新程序替换 从新程序的启动例程开始执行

如何完成这一系列操作?

操作系统的接口exec函数: 加载新程序代码和数据到内存 建立新的映射关系

2.如何完成进程替换

2.1exec系列函数

加载器的底层系统调用接口

#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);

在这里插入图片描述

基于execve的封装–库函数

	   #include <unistd.h>extern char **environ;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 execvpe(const char *file, char *const argv[], char *const envp[]);

在这里插入图片描述

在这里插入图片描述

命名理解

l(list) : 参数采用列表形式
v(vector) : 参数用数组形式
p(path) : 自动搜索环境变量PATH
e(env) : 自己维护环境变量

2.2 int execl(const char *path, const char *arg, …);

1.在当前进程进行替换

 int execl(const char *path, const char *arg, ...);execl: l--list 像结点一样将参数传入可变参数列表path: 路径+目标文件名arg: 可变参数列表 可以传入多个参数(个数不定)调用时:NULL结尾 表示参数传递完毕
  1. execl()函数: 函数调用成功后 当前的代码和数据完全被新程序的代码和数据替换
  2. 函数调用失败后会返回-1(执行原代码 对原代码无影响) 表示调用新程序失败 调用成功没有返回值 因为调用成功后当前代码和数据完全被替换 而execl()就在其中

代码演示

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main()
{printf("当前进程开始运行\n");//execl("/usr/bin/ls", "ls", NULL);execl("/usr/bin/ls", "ls", "-l", "-a", "-i", NULL);//execl("/usr/bin/top", "top", NULL);//execl("/usr/bin/ls", "ls", "--color=auto", "-l", NULL);ls是一个用C语言写的程序 他也有main函数 实际上 这里的传参就是把参数传给了ls程序里的main函数 这也与我们之前讲到的命令行参数的空间布局相呼应 exit(1);printf("当前进程结束!\n");return 0;
}

在这里插入图片描述

为什么在xshell下执行ls 就会有颜色 而在我们的程序里执行ls 还要加"--color=auto"才会有颜色?

因为在bash进程里给ls取了别名 自动就会加"--color=auto"

2.在子进程进行替换

在子进程进行进程替换的目的

  1. 不影响父进程 让父进程聚焦在读取数据,解析数据,指派子进程执行代码
  2. 让子进程被替换的目的是去执行新的程序而不是执行父进程的不同代码 所以让子进程进行替换的目的就是让父进程仍然执行他自己的代码 让子进程执行一个新的程序 并且父进程不受影响

对子进程进行程序替换的理解

  1. 子进程被替换前 父子进程代码共享 数据写时拷贝
  2. 当子进程发生进程替换 会有一份新的程序(代码+数据)完全覆盖子进程原有内容 此时会发生写时拷贝 即当子进程发生进程替换 子进程在物理内存中将会有自己的单独空间(新程序)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>int main(int argc, char*argv[], char *env[])
{pid_t id = fork();if(id == 0){//子进程printf("子进程开始运行, pid: %d\n", getpid());sleep(3);execl("/usr/bin/ls", "ls", "-a", "-l", NULL);exit(1);}else {//父进程printf("父进程开始运行, pid: %d\n", getpid());int status = 0;pid_t id = waitpid(-1, &status, 0);if(id > 0){printf("wait success, exit code: %d\n", WEXITSTATUS(status));}}return 0;
}

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 16
int main(int argc, char*argv[], char *env[])
{pid_t id = fork();if(id == 0){//子进程printf("子进程开始运行, pid: %d\n", getpid());sleep(3);char *const _argv[NUM] = {(char*)"ls",(char*)"-a",(char*)"-l",(char*)"-i",NULL};//execl("/usr/bin/ls", "ls", "-a", "-l", NULL);execv("/usr/bin/ls", _argv);exit(1);}else {//父进程printf("父进程开始运行, pid: %d\n", getpid());int status = 0;pid_t id = waitpid(-1, &status, 0); if(id > 0){printf("wait success, exit code: %d\n", WEXITSTATUS(status));}}return 0;
}

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

自动在环境变量PATH中查找文件名的路径

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 16
int main(int argc, char*argv[], char *env[])
{pid_t id = fork();if(id == 0){//子进程printf("子进程开始运行, pid: %d\n", getpid());sleep(3);char *const _argv[NUM] = {(char*)"ls",(char*)"-a",(char*)"-l",(char*)"-i",NULL};//execl("/usr/bin/ls", "ls", "-a", "-l", NULL);//execv("/usr/bin/ls", _argv); execlp("ls", "ls", "-a", "-l", NULL);exit(1);}else {//父进程printf("父进程开始运行, pid: %d\n", getpid());int status = 0;pid_t id = waitpid(-1, &status, 0); if(id > 0){printf("wait success, exit code: %d\n", WEXITSTATUS(status));}}return 0;
}

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 16
int main(int argc, char*argv[], char *env[])
{pid_t id = fork();if(id == 0){//子进程printf("子进程开始运行, pid: %d\n", getpid());sleep(3);char *const _argv[NUM] = {(char*)"ls",(char*)"-a",(char*)"-l",(char*)"-i",NULL};//execl("/usr/bin/ls", "ls", "-a", "-l", NULL);//execv("/usr/bin/ls", _argv); //和上面的execl只有传参方式的区别//execlp("ls", "ls", "-a", "-l", NULL);execvp("ls", _argv);exit(1);}else {//父进程printf("父进程开始运行, pid: %d\n", getpid());int status = 0;pid_t id = waitpid(-1, &status, 0); if(id > 0){printf("wait success, exit code: %d\n", WEXITSTATUS(status));}}return 0;
}

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

1.Makefile: 一次生成多个可执行程序

在这里插入图片描述

2.子进程中执行自己写的C/C++程序

2.1自己写的C/C++程序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char *argv[])
{if(argc != 2){printf("can not execute!\n");exit(1);}printf("获取环境变量: VIRTUALENV: %s\n", getenv("VIRTUALENV"));if(strcmp(argv[1], "-a") == 0){printf("hello a!\n");}else if(strcmp(argv[1], "-b") == 0){printf("hello b!\n");}else{printf("default!\n");}return 0;
}
2.2执行自己写的C/C++程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 16//const char *fileaddr = "/home/lhr/linux/procreplace/cmd";
const char *fileaddr = "./cmd";int main(int argc, char*argv[], char *env[])
{pid_t id = fork();if(id == 0){//子进程printf("子进程开始运行, pid: %d\n", getpid());sleep(3);char *const _argv[NUM] = {(char*)"ls",(char*)"-a",(char*)"-l",(char*)"-i",NULL};execle(fileaddr, "cmd", "-a", NULL);//execle(fileaddr, "cmd", "-a", NULL);//execl("/usr/bin/ls", "ls", "-a", "-l", NULL);//execv("/usr/bin/ls", _argv); //和上面的execl只有传参方式的区别//execlp("ls", "ls", "-a", "-l", NULL);//execvp("ls", _argv);exit(1);}else {//父进程printf("父进程开始运行, pid: %d\n", getpid());int status = 0;pid_t id = waitpid(-1, &status, 0); if(id > 0){printf("wait success, exit code: %d\n", WEXITSTATUS(status));}}return 0;
}

3.子进程中执行自己写的py/sh程序

test.py
#! /usr/bin/python3.6
print("hello Python")
print("hello Python")
print("hello Python")test.sh
#! /usr/bin/bash
echo "hello shell!"
echo "hello shell!"
echo "hello shell!"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 16int main(int argc, char*argv[], char *env[])
{pid_t id = fork();if(id == 0){//子进程printf("子进程开始运行, pid: %d\n", getpid());sleep(3);在命令行下: python test.py === ./test.py (自动调用解释器)//execlp("./test.py", "test.py", NULL);//execlp("bash", "bash", "test.sh", NULL);//execlp("python", "python", "test.py", NULL);py/sh/java: 有解释器 在解释器(也是一个程序)内编译执行对应程序exit(1);}else {//父进程printf("父进程开始运行, pid: %d\n", getpid());int status = 0;pid_t id = waitpid(-1, &status, 0); if(id > 0){printf("wait success, exit code: %d\n", WEXITSTATUS(status));}}return 0;
}

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

4.1自己写的C/C++程序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char *argv[])
{if(argc != 2){printf("can not execute!\n");exit(1);}printf("获取环境变量: VIRTUALENV: %s\n", getenv("VIRTUALENV"));if(strcmp(argv[1], "-a") == 0){printf("hello a!\n");}else if(strcmp(argv[1], "-b") == 0){printf("hello b!\n");}else{printf("default!\n");}return 0;
}
4.2执行自己写的C/C++程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 16//const char *fileaddr = "/home/lhr/linux/procreplace/cmd";
const char *fileaddr = "./cmd";int main(int argc, char*argv[], char *env[])
{pid_t id = fork();if(id == 0){//子进程printf("子进程开始运行, pid: %d\n", getpid());sleep(3);char *const _env[NUM] = {(char*)"VIRTUALENV=547993",NULL};char *const _argv[NUM] = {(char*)"ls",(char*)"-a",(char*)"-l",(char*)"-i",NULL};execle(fileaddr, "cmd", "-a", NULL, env);//execle(fileaddr, "cmd", "-a", NULL, _env);exit(1);}else {//父进程printf("父进程开始运行, pid: %d\n", getpid());int status = 0;pid_t id = waitpid(-1, &status, 0);if(id > 0){printf("wait success, exit code: %d\n", WEXITSTATUS(status));}}return 0;
}

2.7 int execvpe(const char *file, char *const argv[], char *const envp[]);

同上类比

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

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

相关文章

分治—快速选择算法

文章目录 &#x1f347;215.数组中的第K个最大元素&#x1f348;1. 题目&#x1f349;2. 算法原理&#x1f34a;3. 代码实现 &#x1f34b;LCR 159. 库存管理 III&#x1f34c;1. 题目&#x1f34d;2. 算法原理&#x1f96d;代码实现 &#x1f347;215.数组中的第K个最大元素 …

损失函数代价函数

代价函数&#xff08;Cost Function&#xff09;和损失函数&#xff08;Loss Function&#xff09;是深度学习中两个相关但不完全相同的概念&#xff0c;它们用于衡量模型的性能&#xff0c;并在训练过程中进行参数优化。尽管经常被混用&#xff0c;但在一些文献中也有区别对待…

强推六款满分AI写作工具,需要自取

&#x1f517; 运行环境&#xff1a;ChatGPT &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 &#x1f510;#### 防伪水印——左手の明天 ####&#x1f510; &#x1f497; 大家…

31-WEB漏洞-文件操作之文件包含漏洞全解

31-WEB漏洞-文件操作之文件包含漏洞全解 一、本地包含1.1、无限制包含漏洞文件1.2、有限制包含漏洞文件1.2.1、绕过方法1.2.1.1、%00截断1.2.1.2、长度截断 二、远程包含2.1、无限制包含漏洞文件2.2、有限制包含漏洞文件 三、各种协议流提交流3.1、各协议的利用条件和方法3.1.1…

克服.360勒索病毒:.360勒索病毒的解密和预防

导言: 在数字化的今天&#xff0c;数据安全问题变得愈发棘手。.360勒索病毒是当前网络空间的一场潜在灾难&#xff0c;对于这个威胁&#xff0c;了解应对之道和采取切实的预防措施至关重要。如果您正在经历勒索病毒的困境&#xff0c;欢迎联系我们的vx技术服务号&#xff08;s…

洛谷 P5711 闰年判断 C++代码

目录 前言 思路点拨 AC代码 结尾 前言 今天我们来做洛谷上的一道题目。 网址&#xff1a;【深基3.例3】闰年判断 - 洛谷 题目&#xff1a; 思路点拨 首先题目让我们输入一个年份&#xff0c;因此我们需要定义一个变量year&#xff0c;来存储输入的年份&#xff1a; in…

回归分析:预测和建模

回归分析:预测和建模 写在开头1. 回归分析的基本概念2. 回归分析的方法2.1 简单线性回归2.1.1 数学知识2.1.2 应用举例2.2 多元线性回归2.2.1 数学公式和应用2.2.1 应用场景举例2.3 多项式回归2.3.1 数学公式和应用2.3.2 应用场景举例2.4 逻辑回归2.4.1 数学公式和应用2.4.2 应…

matlab科学计算

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

如何进行卷积特征可视化

大家好啊&#xff0c;我是董董灿。 之前写过很多关于卷积算法的文章&#xff1a;5分钟理解什么是卷积的特征提取。总的来说&#xff0c;卷积算法的本质是一个特征提取器。 那么既然卷积神经网络在图像分类、图像检测、图像分割以及其他领域有这么好的表现&#xff0c;卷积到底…

【动手学深度学习】(六)权重衰退

文章目录 一、理论知识二、代码实现2.1从零开始实现2.2简洁实现 【相关总结】 主要解决过拟合 一、理论知识 1、使用均方范数作为硬性限制&#xff08;不常用&#xff09; 通过限制参数值的选择范围来控制模型容量 通常不限制偏移b 小的意味着更强的正则项 使用均方范数作为柔…

多项式拟合求解

目录 简介 基本原理 例1 例2 例3 参考资料 简介 多项式拟合可以用最小二乘求解&#xff0c;不管是一元高阶函数&#xff0c;还是多元多项式函数&#xff0c;还是二者的混合&#xff0c;都可以通过统一的方法求解。当然除了最小二乘法&#xff0c;还是其他方法可以求解&…

极兔速递查询,极兔速递单号查询,根据更新量筛选出来需要的单号

批量查询极兔速递单号的物流信息&#xff0c;并根据物流更新量将需要的单号筛选出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 极兔速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;第一次使用的伙伴记得先注册&…

express搭建后台node接口

在前端的学习中我们使用express来开发接口结合mysql&#xff0c;然后使用可视化的数据库工具来操作数据&#xff0c; web框架是express 文档是jsdoc swagger 数据库模型是sequelize 部署使用PM2来上服务器&#xff0c; 打包你也可以结合webpack配置target node状态 当然你也可以…

糟了,数据库崩了,又好像没崩

前言 2023 年某一天周末&#xff0c;新手程序员小明因为领导安排的一个活来到公司加班&#xff0c;小明三下五除二&#xff0c;按照领导要求写了一个跑批的数据落库任务在测试环境执行 &#xff0c;突然间公司停电了&#xff0c;小明大惊&#xff0c;“糟了&#xff0c;MySQL …

cc-product-waterfall仿天猫、淘宝购物车店铺商品列表组件

cc-product-waterfall仿天猫、淘宝购物车店铺商品列表组件 引言 在电商应用中&#xff0c;购物车体验的优化对于提升用户满意度和转化率至关重要。在本文中&#xff0c;我们将深入探讨如何使用cc-product-waterfall组件&#xff0c;结合uni-number-box和xg-widget&#xff0c;…

软著项目推荐 深度学习手势识别算法实现 - opencv python

文章目录 1 前言2 项目背景3 任务描述4 环境搭配5 项目实现5.1 准备数据5.2 构建网络5.3 开始训练5.4 模型评估 6 识别效果7 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习手势识别算法实现 - opencv python 该项目较为新颖…

计算机网络 | 物理层下 传输媒介、信道复用技术,带宽接入技术

文章目录 3. 物理层下面的传输媒介3.1 导引型传输媒介3.2 非导引型传输媒介 4 信道复用技术5 数字传输系统5.1 旧的数字系统5.2 新数字系统 6 带宽接入技术6.1 DSL&#xff08;数字用户线&#xff09;6.2HFC 光纤同轴混合网6.2.1 接入 6.3 FTTx技术 3. 物理层下面的传输媒介 传…

FL Studio 21.2.1.3859中文破解激活版2024免费下载安装图文教程

FL Studio 21.2.1.3859中文破解激活版是我见过更新迭代最快的宿主软件&#xff0c;没有之一。FL Studio12、FL Studio20、FL Studio21等等。有时甚至我刚刚下载好了最新版本&#xff0c;熟悉了新版本一些好用的操作&#xff0c;Fl Studio就又推出了更新的版本&#xff0c;而且F…

WebGL笔记:矩阵平移的数学原理和实现

矩阵平移的数学原理 让向量OA位移 x方向&#xff0c;txy方向&#xff0c;tyz方向&#xff0c;tz 最终得到向量OB 矩阵平移的应用 再比如我要让顶点的x移动0.1&#xff0c;y移动0.2&#xff0c;z移动0.3 1 &#xff09;顶点着色器核心代码 <script id"vertexShader&…

面试官:说说Vue中Proxy与Object.defineProperty的用法与区别

前言 面试时&#xff0c;我们说完Vue响应式原理&#xff0c;或者Vue2和Vue3的区别时&#xff0c;通常会引出Vue3使用了Proxy来优化响应式&#xff0c;而面试官会继续深挖&#xff1a;说说Proxy与Object.defineProperty的区别。 我们不能只说Proxy直接代理一个对象&#xff0c…