进程的程序替换(exec函数)【Linux】

进程的程序替换详解exec函数【Linux】

  • 程序替换的原理
  • exec系列函数
    • 函数理解
    • 命令理解(助记)
  • 关于程序替换中环境变量的解释
  • exec函数之间的关系
  • exec函数的使用
    • execl
    • execlp
    • execle
    • execv

程序替换的原理

  进程的程序替换就是让子进程执行新程序, 执行全新的代码和数据,不再和父进程有瓜葛。
替换原理

  用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
在这里插入图片描述

  • 也就是说程序替换的作用是为了完成一些特定的任务,需要去执行其他的程序。
  • 使用exec系列函数可以达到程序替换的目的。
  • 程序替换会重新创建虚拟地址,页表,然后将磁盘中的文件加载进物理内存。
  • 程序替换会自动释放原来的进程虚拟内存和页表。
  • 程序替换时, 虚拟地址空间和页表的映射会变化,PCB里的优先级等信息不变。

exec系列函数

  以下函数的参数末尾都一定需要带上一个==“NULL”==。

#include <unistd.h>// path是要替换的程序文件路径+文件名,main函数的argv参数中是什么,这里就怎么写。
int execl(const char *path, const char *arg, ...);// 会自动到环境变量PATH中根据file寻找新程序的文件,所以file可以直接写成文件名即可。
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[]);

函数理解

  • 这些函数执行成功的话,则加载进新的程序,启动新程序并且从新程序的的开头开始执行,不再返回。
  • 如果执行成功,原程序中的后续代码将不再执行,因为eip(程序计数器),已经改变到新程序处。
  • 如果调用出错则返回-1.
  • 所以exec只有出错的返回值没有成功的返回。毕竟成功的返回值是无意义的。
  • 除了系统文件,也可以替换成自定义文件,如: .sh,python,java都可以调用。

命令理解(助记)

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

  • v(vector) : 参数用数组

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

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

    在这里插入图片描述

关于程序替换中环境变量的解释

  1. 当进行程序替换时,子进程对应的原始环境变量是从父进程中来的,bash拥有最原始的环境变量,后代进程可在其基础上添加并继承自己的父进程的环境变量。
  2. 环境变量被继承是一种默认行为,不受程序替换的影响。(程序替换只替换代码和数据,不替换环境变量)因为创建子进程都以父进程为模板,父子进程的环境变量指向同一块物理地址,所以一样。
  3. 如何让子进程获得环境变量。
  • 将父进程的环境变量原封不动的传递给子进程(1. 直接用。 2. 直接传)。
  • 想传递自己的环境变量,可以直接构建环境变量表,给子进程传递(是覆盖原来环境变量式的传递)
  • 新增传递(可以利用putenv()函数)。

exec函数之间的关系

  事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve,所以execve, man手册 第2节,其它函数在man手册第3节。这些函数之间的关系如下图所示。

下图exec函数族 一个完整的例子:

在这里插入图片描述

exec函数的使用

execl

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

// test.cpp:
#include <iostream>
#include <unistd.h>
int main()
{pid_t fd = fork();if (fd == 0){// childexecl("/root/Y23_12_28/t", "t", "-start", NULL);}return 0;
}
#include <stdio.h>int main(int argc, char *argv[])
{printf("%s %s\n", argv[0], argv[1]);printf("我是t.cpp进程\n");return 0;
}

在这里插入图片描述

execlp

int execlp(const char *file, const char *arg, ...);
此时我们打印环境变量PATH:

#include <stdio.h>
#include <unistd.h>
#include <cstdlib>
int main(int argc, char *argv[])
{printf("%s", getenv("PATH"));return 0;
}

在这里插入图片描述
打印当前的文件路径cwd:
在这里插入图片描述
  对比会发现PATH中没有cwd,若是直接使用execlp的话一定会报错。我们来试一下:

#include <stdio.h>
#include <unistd.h>
int main()
{pid_t fd = fork();if (fd == 0){// childint ret = execlp("t", "t", "-start", NULL);if (ret < 0){printf("execpl错误\n");}}return 0;
}

在这里插入图片描述
  果然报错了,原因是PATH中没有cwd,无法自动找到文件位置。所以我们需要添加环境变量,使用putenv()函数,使用这个函数需要注意的是,会将原来的PATH内容全部清除,然后再添加新的PATH。

//test.cpp:
#include <stdio.h>
#include <unistd.h>
#include <cstdlib>
int main()
{pid_t fd = fork();if (fd == 0){char *old_PATH = getenv("PATH");char new_PATH[] = ":/root/Y23_12_28";char new1[1000];sprintf(new1, "PATH=%s%s", old_PATH, new_PATH);putenv(new1);// childint ret = execlp("t", "t", "-start", NULL);if (ret < 0){printf("execpl错误\n");}}return 0;
}
//t.cpp:
#include <stdio.h>
#include <cstdlib>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{printf("%s %s\n", argv[0], argv[1]);printf("我是t.cpp进程\n");return 0;
}

  这里有一个需要注意的地方,就是合并新老PATH时,一定不要忘记PATH=%s%sPATH=
在这里插入图片描述

execle

int execle(const char *path, const char *arg, ...,char *const envp[]);
  多出来的这个e表明了可以自己设定环境变量:

// test.cpp
#include <stdio.h>
#include <unistd.h>
#include <cstdlib>
int main()
{pid_t fd = fork();if (fd == 0){char *const envp[] = {"PATH=/root/Y23_12_28", "NULL"};// childint ret = execle("t", "t", "-start", NULL);if (ret < 0){printf("execpl错误\n");}}return 0;
}

在这里插入图片描述

execv

int execv(const char *path, char *const argv[]);
  v表示使用数组来装载命令, 而不是vector;

#include <stdio.h>
#include <unistd.h>
#include <cstdlib>int main()
{pid_t fd = fork();if (fd == 0){// childchar *arg[3] = {"t", "-start", "NULL"};int ret = execv("/root/Y23_12_28/t", arg);if (ret < 0){printf("execpl错误\n");}}return 0;
}

在这里插入图片描述
  至于execvp和execve在这里就不过多赘述了。


    😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄

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

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

相关文章

C 语言用户输入详解:scanf、fgets、内存地址解析及实用指南

C 语言中的用户输入 您已经学习了 printf() 函数用于在 C 语言中输出值。 要获取用户输入&#xff0c;可以使用 scanf() 函数&#xff1a; // 声明一个整数变量&#xff0c;用于存储我们从用户那里获得的数字 int myNum;// 提示用户输入一个数字 printf("请输入一个数字…

Java 8 新特性

Java 8 新特性 Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 &#xff0c;它支持 函数式编程&#xff0c;新的 JavaScript 引擎&#xff0c;新的日期 API&#xff0c;新的Stream API 等。 1、新特性 Java8 新增…

QT_02 窗口属性、信号槽机制

QT - 窗口属性、信号槽机制 1. 设置窗口属性 窗口设置 1,标题 2,大小 3,固定大小 4,设置图标在 widget.cpp 文件中&#xff1a; //设置窗口大小,此时窗口是可以拉大拉小的 //1参:宽度 //2参:高度 this->resize(800, 600); //设置窗口标题 this->setWindowTitle("…

Docker中的核心概念

1.镜像 Image 一个镜像就代表一个软件。mysql镜像、redis镜像、mq镜像 2.容器 Container 一个镜像运行一次就会生成一个容器&#xff0c;容器就是一个运行的软件服务。 3.远程仓库 Repository 远程仓库用来存储所有软件的镜像&#xff0c;Docker Hub 4.本地仓库 用来存储…

Ubuntu18.04配置静态ip

文章目录 查看网卡名、ip地址、网关切换root用户&#xff0c;进入配置文件配置静态IP 查看网卡名、ip地址、网关 首先查看网卡名、ip地址、网关&#xff0c;找到对应的网卡名并记录其地址 ifconfigroute -n切换root用户&#xff0c;进入配置文件 sudo -icd /etc/netplanvim …

Linux系统中MYSQL重置密码(针对root忘记密码)

⼀ .进⼊MySql配置⽂件中 vi /etc/my.cnf 在最后⼀⾏添加免密码登陆: skip-grant-tables :wq 保存退出 ⼆.重启MySql service mysql restart 或 systemctl restart mysqld.service 三. 登陆数据库 mysql -uroot -p 让输⼊密码直接回⻋就可以 四.修改MySql密码 use mysql…

听GPT 讲Rust源代码--compiler(11)

File: rust/compiler/rustc_mir_transform/src/simplify.rs 在Rust源代码中&#xff0c;rust/compiler/rustc_mir_transform/src/simplify.rs文件是Rust编译器中一系列进行MIR&#xff08;中间表示&#xff09;简化的转换的实现。MIR是Rust编译器中用于进行优化和代码生成的中间…

开源大数据集群部署(一)集群实施规划

作者&#xff1a;櫰木 本次集群规划信息 本次实际生产业务体量存在巨大差异&#xff0c;但集群规划内容相同&#xff0c;因此建议实际生产环境按照按照一定比例扩展即可。 主机操作系统要求 软件信息参数配置8C16G操作系统版本CentOS Linux release 7.8.2003 (Core)java版本…

深入理解 BEM:前端开发中的命名约定革命

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Python+OpenCV 零基础学习笔记(6):ROI

文章目录 相关链接运行环境前言ROI颜色区域分割颜色通道合并 相关链接 【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程 CSDN标题里个括号对应视频的分P OpenCVPython CSDN专栏 Gitee 项目地址 运行环境 Python:3.11.5Anaconda:23.7.4IDE:vscode运行环境&#x…

长虹智能电视41机芯(PM41i)强制刷机升级

适配型号&#xff1a; 3D51C4000i 3D60C4000i 3D60C4300i 升级方法&#xff1a; 第 1 步&#xff0c;将升级程序拷贝到U 盘根目录下&#xff0c;请保持根目录升级文件的唯一性文件名必须采用&#xff1a;chandroid_ota_PM41i_datapart.zip、upgrade_PM41i_EMMC_V1.00010_part…

WebSocket的优点和缺点:一文详解。

WebSocket 的优缺点 WebSocket 协议是一种双向通信协议&#xff0c;它使用单个 TCP 连接实现全双工通信&#xff0c;这使它比传统的 HTTP 协议更有效率。 WebSocket 优点 双向通信&#xff1a; WebSocket 协议支持双向通信&#xff0c;使服务器和客户端之间的通信更加方便和快…

Elasticsearch 中映射参数doc_values 和 fielddata分析比较

一、doc_values 默认情况下&#xff0c;大部分字段是索引的&#xff0c;这样让这些字段可被搜索。倒排索引&#xff08;inverted index&#xff09;允许查询请求在词项列表中查找搜索项&#xff08;search term&#xff09;&#xff0c;并立即获得包含该词项的文档列表。 倒排…

vscode 格式化代码后反而出现红色波浪线格式报错

表现&#xff1a; vscode 代码文件格式化之后&#xff0c;反而出现红色波浪线&#xff0c;提示 应该换行/缩进不正确 等等格式不规范之类的信息。 原因&#xff1a; 因为同时开启了两个格式化插件&#xff0c;且两者的规则有冲突。 就我自己的情况而言&#xff1a;格式化代…

漫谈广告机制设计 | 【预告】万剑归宗:机制设计提高平台广告收入的绝招

读者们好&#xff0c;新年快乐&#xff0c;祝大家新的一年工作顺利&#xff0c;万事如意。 假期更新了两篇文章oCPC实践录 | 以基木鱼为例谈线索类有效转化的设计与智能客服的问题和oCPC实践录 | 目标ROI的出价与转化回传调控算法&#xff0c;欢迎讨论、评论、点赞、分享、转发…

2023年为何YOLO成为最热门视觉检测技术?猫头虎带您揭秘其背后的原因!

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通Golang》…

查询运行的java程序线程总数

&#xff08;1&#xff09;方法一 ps -ef|grep java pstree -p pid|wc -l 安装pstree包&#xff0c;yum install psmisc &#xff08;2&#xff09;方法二 top -H -p pid

golang 性能优化

1. 临时变量使用 var 声明&#xff0c; 慎用new&#xff0c; new是从堆上分配内存&#xff0c;效率略差。 2. 遍历切片用索引&#xff0c;不用for range 3. 切片&#xff0c;map最好用多少空间分配多少空间&#xff0c;避免多次分配影响性能

互联网分布式应用之RabbitMQ

RabbitMQ Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. RabbitMQ介绍安装 2. Rabbi…

人工智能在金融领域的应用存在的4大挑战

金融服务供应商应该有计划地应对AI面临的难题 金融行业投资人工智能热潮带来有关数据安全和透明度的新问题。由于数据管理实践随着新的 AI 解决方案的引入而不断发展&#xff0c;应对这些新问题以及金融服务领域 AI 面临的其他挑战尤为重要。各组织必须认识到可能面临以下挑战…