Linux - 进程控制(进程替换)

0.引入

创建子进程的目的是什么?

就是为了让子进程帮我执行特定的任务

让子进程执行父进程的一部分代码
如果子进程想执行一个全新的程序代码呢? 那么就要使用 进程的程序替换

为什么要有程序替换?

也就是说子进程想执行一个全新的程序代码!

这份代码看似是子进程的代码,其实也是父进程的代码,只是父进程通过id的值进行判断,让子进程运行。

1.替换原理

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

当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动 例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

2.替换函数

其实有六种以exec开头的函数,统称exec函数:

使用man手册查看相关exec函数

execl最后的...参数,表示可变参数列表,可以给C函数传递任意的参数

execl


int execl(const char *path, const char *arg, ...);
  • path:新程序的路径和名称。

  • arg0 ~ argn:新程序的命令行参数列表,以 NULL 结尾。arg0 表示新程序的名称,arg1 ~ argn 表示新程序的各个参数。

为什么只看到了begin()... end...为什么不显示呢?

执行程序替换,新的代码和数据都被加载了,后续的代码属于老代码,直接被替换了,没机会执行了

并且程序替换是整体替换,不能局部替换!!!

ls是磁盘上的可执行程序,execl调用了ls-la

把当前的代码和数据,从execl到磁盘中进行替换

问题:进程的程序替换,有没有创建新的进程呢?

没有!!

为什么呢?很简单,因为我只是把一个新的程序加载到我们当前进程所对应的代码和数据段,我就让CPU去调度当前进程,就可以跑起来了。其中,我们并没有创建新的进程。当前的进程PID没有变化

这是站在进程的角度来看的

那么站在程序的角度呢? -- 这个程序被加载到内存里了

所以,我们也可以说execl是加载器

问题:当创建进程的时候,先加载进程数据结构,还是先加载代码和数据?

在创建进程时,操作系统通常会先创建进程数据结构,然后再加载代码和数据。

这里代码,子进程里的execl替换代码,会影响父进程吗?

不会,程序替换只会影响调用进程,进程具有独立性

子进程加载新程序的时候,是需要进行程序替换的,发生写时拷贝(子进程执行的可是全新的程序,新的代码,写时拷贝在代码区也可以发生)

execl函数调用失败,会发生什么?

我们写一个代码,让程序故意发生错误

父进程获取子进程退出码

接下来开始熟悉所有的接口

execv


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

execv() 函数接受两个参数。第一个参数是要执行的程序的路径,第二个参数是传递给新程序的命令行参数。这些参数以一个字符串数组的形式传递给函数。

注意:当execv调用失败的话,程序继续执行

execlp


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

其中,file 参数表示要执行的可执行文件的名称,arg 参数表示传递给该可执行文件的命令行参数,最后的参数为可变参数列表,表示该命令行参数以 NULL 结束。

execlp 函数会在 PATH 环境变量指定的路径中查找可执行文件,因此无需指定可执行文件的完整路径。如果 PATH 环境变量中有多个路径,则 execlp 函数会按照路径的顺序查找可执行文件。


execlp("ls","ls","-a","-l","-n",NULL);

这里的两个ls分别是什么意思?

第一个是系统环境变量路径ls,第二个是ls指令

等同于以下代码

execle


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

该函数接收以下参数:

  • path:要执行的程序的路径名。

  • arg0:新程序的第一个参数,通常是新程序的名称。

  • arg1~argn:新程序的参数列表。

  • envp:新程序的环境变量数组。

该函数的返回值是一个整数,如果成功执行,则永远不会返回。如果出现错误,则会返回-1,并设置errno来指示错误的类型。

envp[]数组是自定义环境变量

execvp

函数原型如下:


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

该函数会在PATH环境变量指定的路径中搜索指定的可执行文件,并在找到文件后将当前进程替换为该可执行文件。

其中,file参数是一个字符串,指定要执行的可执行文件的路径和文件名。argv参数是一个指向字符串数组的指针,其中第一个字符串表示可执行文件的名称,后面的字符串表示传递给可执行文件的命令行参数。

execvpe

函数原型如下:


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

file 参数是要执行的可执行文件的路径,argv 参数是一个指向参数列表的指针数组,envp 参数是一个指向环境变量列表的指针数组。

execvpe 函数首先会搜索 PATH 环境变量中指定的目录,找到可执行文件后,它会用新的进程替换当前进程,并开始执行新的程序。在新的进程中,参数和环境变量都被设置成 argvenvp 中指定的值。

execvpe 函数和其他 exec 系列函数的主要区别在于它会搜索 PATH 环境变量中指定的目录来查找可执行文件,并且可以设置环境变量。

execve

函数原型如下:


int execve(const char *filename, char *const argv[], char *const envp[]);

filename 参数是要执行的可执行文件的路径,argv 参数是一个指向参数列表的指针数组,envp 参数是一个指向环境变量列表的指针数组。

execve 函数会用新的进程替换当前进程,并开始执行新的程序。在新的进程中,参数和环境变量都被设置成 argvenvp 中指定的值。

execve 函数不会搜索 PATH 环境变量中指定的目录来查找可执行文件,它只会使用 filename 参数中指定的路径来查找可执行文件。如果指定的文件路径不是一个可执行文件,那么该函数会返回一个错误。

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

3.调用自定义程序

上面都是执行命令。能否执行我自己写的程序呢?

用C语言调用C++写的可执行程序

可以发现PID是一模一样的,替换了C++程序,没有创建新的进程

接下来尝试在C++程序中获取环境变量

获取环境变量。C++的cout如果环境变量不存在,就什么都不会打印,所以要进行判断,如果没有就打印NULL

修改下C程序,在C程序中自定义环境变量表,使用execle函数

问题:C语言调用C++可以调用到环境变量吗?

修改下C++代码,获取环境变量

C++自己写的里有PATH,但没有环境变量

观察下C语言的

C语言调用的有MYENV 但是没有PATH

调用的环境变量是覆盖式写入,会覆盖老的环境变量PATH,所以看不到PATH

传系统环境变量

C语言提供的环境变量表,二级指针,environ

此时MYENV就没有了,系统的环境变量出现了

系统环境变量和自定义环境变量同时传递

利用putenv添加到系统环境变量里,依赖头文件#include<stdlib.h>

putenv将MYENV传到系统变量里,这样调用系统变量,就可以将自定义和系统变量一块传递给替换程序

环境变量具有全局属性,可以被子进程继承下去!
就是 通过execle函数传递的环境变量!
使用export MYENV = You can see me   也可以

4.exec函数解释

1.这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
2.如果调用出错则返回-1
3.所以exec函数只有出错的返回值而没有成功的返回值。

5.命名理解

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

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

exec调用举例如下:


#include <unistd.h>
int main()
{char *const argv[] = {"ps", "-ef", NULL};char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};execl("/bin/ps", "ps", "-ef", NULL);// 带p的,可以使用环境变量PATH,无需写全路径execlp("ps", "ps", "-ef", NULL);// 带e的,需要自己组装环境变量execle("ps", "ps", "-ef", NULL, envp);execv("/bin/ps", argv);// 带p的,可以使用环境变量PATH,无需写全路径execvp("ps", argv);// 带e的,需要自己组装环境变量execve("/bin/ps", argv, envp);exit(0);
}

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

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

相关文章

HCIP OSPF+BGP综合实验

题目 1、该拓扑为公司网络&#xff0c;其中包括公司总部、公司分部以及公司骨干网&#xff0c;不包含运营商公网部分。 2、设备名称均使用拓扑上名称改名&#xff0c;并且区分大小写。 3、整张拓扑均使用私网地址进行配置。 4、整张网络中&#xff0c;运行OSPF协议或者BGP协议…

python森林生物量(蓄积量)数据处理到随机森林估算全流程

python森林生物量&#xff08;蓄积量&#xff09;估算全流程 一.哨兵2号获取/处理/提取数据1.1 影像处理与下载采用云概率影像去云采用6S模型对1C级产品进行大气校正geemap下载数据到本地NDVI 1.2 各种参数计算&#xff08;生物物理变量、植被指数等&#xff09;LAI&#xff1a…

抖音引流推广的几个方法,抖音全自动引流脚本软件详细使用教学

大家好我是你们的小编一辞脚本&#xff0c;今天给大家分享新的知识&#xff0c;很开心可以在CSDN平台分享知识给大家,很多伙伴看不到代码我先录制一下视频 在给大家做代码&#xff0c;给大家分享一下抖音引流脚本的知识和视频演示 不懂的小伙伴可以认真看一下&#xff0c;我们…

【C++】总结9

文章目录 C从源代码到可执行程序经过什么步骤静态链接和动态链接类的对象存储空间C的内存分区内存池在成员函数中调用delete this会出现什么问题&#xff1f;如果在类的析构函数中调用delete this&#xff0c;会发生什么&#xff1f; C从源代码到可执行程序经过什么步骤 预处理…

java学习路程之篇六、进阶知识、常用API、Arrays工具类、冒泡排序、选择排序、二分查找、正则表达式

文章目录 1、Arrays工具类2、冒泡排序3、选择排序4、二分查找5、正则表达式 1、Arrays工具类 2、冒泡排序 3、选择排序 4、二分查找 5、正则表达式

【Maven】Nexus3上传maven依赖jar

后端依赖 上次说到前端的批量tgz文件上传私服&#xff0c;其实服务端也有类似情况&#xff0c;我们有个私服也需要进行上传到私服&#xff0c;这里做个记录。因为上次有个小细节没注意白白传错了一遍&#xff0c;这里重新记录总结一下。 # 查看一下结构 $ tree -L 2 . |-- re…

【vue】 Tinymce 富文本编辑器 不想让上传的图片转换成base64,而是链接

前言&#xff1a;最近项目上需要使用富文本编辑器&#xff0c;觉得tinymce很不错就用了&#xff0c;具体怎么在项目中使用参考 【vue】 vue2 中使用 Tinymce 富文本编辑器 【vue】 Tinymce 数据 回显问题 | 第一次正常回显后面&#xff0c;显示空白bug不能编辑 这两天又遇到了…

Windows下RocketMQ的启动

下载地址&#xff1a;下载 | RocketMQ 解压后 一、修改runbroker.cmd 修改 bin目录下的runbroker.cmd set "JAVA_OPT%JAVA_OPT% -server -Xms2g -Xmx2g" set "JAVA_OPT%JAVA_OPT% -XX:MaxDirectMemorySize15g" set "JAVA_OPT%JAVA_OPT% -cp %CLASSP…

八大排序算法--希尔排序(动图理解)

目录 希尔排序 概念 算法思路 动画演示 代码如下 复杂度分析 时间复杂度测试 运行结果 完整代码 创作不易&#xff0c;如果本篇博客对您有一定的帮助&#xff0c;大家记得留言点赞哦。 希尔排序 概念 希尔排序是插入排序的一种&#xff0c;是对直接插入排序的优化。其…

ChinaJoy 2023微星雷鸟17游戏本震撼发布:搭载AMD锐龙9 7945HX首发8499元

ChinaJoy 2023展会中微星笔记本再次给大家带来惊喜&#xff0c;发布了搭载AMD移动端16大核的旗舰游戏本&#xff1a;雷鸟17&#xff0c;更重要的这样一款旗舰性能的游戏本&#xff0c;首发价8499元堪称当今游戏本市场中的“性价比爆款”&#xff01; 本着和玩家一同制霸游戏战场…

k8s概念-StatefulSet

StatefulSet 是用来管理有状态应用的控制器 StatefulSet 用来管理某Pod集合的部署和扩缩&#xff0c; 并为这些 Pod 提供持久存储和持久标识符StatefulSet | KubernetesStatefulSet 运行一组 Pod&#xff0c;并为每个 Pod 保留一个稳定的标识。 这可用于管理需要持久化存储或稳…

【设计模式——学习笔记】23种设计模式——代理模式Proxy(原理讲解+应用场景介绍+案例介绍+Java代码实现)

介绍 基础介绍 代理模式为一个对象提供一个代理对象&#xff0c;以控制对这个对象的访问。即通过代理对象访问目标对象&#xff0c;这样做的好处是&#xff1a;可以在不修改目标对象代码的基础上&#xff0c;增强额外的功能操作&#xff0c;即扩展目标对象的功能被代理的对象…

牛客网Verilog刷题——VL52

牛客网Verilog刷题——VL52 题目答案 题目 请编写一个十进制计数器模块&#xff0c;当mode信号为1&#xff0c;计数器输出信号递增&#xff0c;当mode信号为0&#xff0c;计数器输出信号递减。每次到达0&#xff0c;给出指示信号zero。模块的接口信号图如下&#xff1a; 模块的…

Flask学习笔记_异步论坛(四)

Flask学习笔记_异步论坛&#xff08;四&#xff09; 1.配置和数据库链接1.exts.py里面实例化sqlalchemy数据库2.config.py配置app和数据库信息3.app.py导入exts和config并初始化到app上 2.创建用户模型并映射到数据库1.models/auth.py创建用户模型2.app.py导入模型并用flask-mi…

教师工作量管理系统Springmvc+Spring+Mybatis课程工作量教室java源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 教师工作量管理系统SpringmvcSpringMybatis 系统有1权…

快速开发人脸识别系统Java版本

简介&#xff1a; 先说下什么是人脸识别系统&#xff1a;举个例子&#xff0c;公司门口有个人脸识别系统&#xff0c;员工站到门口&#xff0c;看着摄像头&#xff0c;大屏幕上会抓拍到你的人脸&#xff0c;然后和公司的员工照片库里的照片比对&#xff0c;比对成功就提示&…

ThreadLocal原理

ThreadLocal原理 ThreadLocal对象new出来存放到堆中&#xff0c;ThreadLocal引用是存放在栈里 Thread 类有个 ThreadLocalMap 成员变量&#xff0c;Map的key是Threadlocal 对象&#xff0c;value是你要存放的线程局部变量。 public void set(T value) {//获取当前线程Thread&…

python爬虫(四)_urllib2库的基本使用

本篇我们将开始学习如何进行网页抓取&#xff0c;更多内容请参考:python学习指南 urllib2库的基本使用 所谓网页抓取&#xff0c;就是把URL地址中指定的网络资源从网络流中读取出来&#xff0c;保存到本地。在Python中有很多库可以用来抓取网页&#xff0c;我们先学习urllib2。…

从零开始学python(十三)爬虫工程师自动化和抓包

前言 回顾之前讲述了python语法编程 必修入门基础和网络编程&#xff0c;多线程/多进程/协程等方面的内容&#xff0c;后续讲到了数据库编程篇MySQL&#xff0c;Redis&#xff0c;MongoDB篇&#xff0c;和机器学习&#xff0c;全栈开发&#xff0c;数据分析&#xff0c;爬虫数…

Go项目实现日志按时间及文件大小切割并压缩

关于日志的一些问题: 单个文件过大会影响写入效率&#xff0c;所以会做拆分&#xff0c;但是到多大拆分? 最多保留几个日志文件&#xff1f;最多保留多少天&#xff0c;要不要做压缩处理&#xff1f; 一般都使用 lumberjack[1]这个库完成上述这些操作 lumberjack //info文件wr…