linux进程控制——进程替换——exec函数接口

        前言: 本节内容进入linux进程控制板块的最后一个知识点——进程替换。 通过本板块的学习, 我们了解了进程的基本控制方法——进程创建, 进程退出, 进程终止, 进程替换。

        进程控制章节和上一节进程概念板块都是在谈进程, 也就是说, 进程的相关内容博主整整通过两个大章, 一共12篇文章进行讲解, 并且几乎每一篇的字数都达到了纯论述五千字左右, 少的也有3500字以上, 多的甚至将近破7000。由此可以看到进程非常重要以及学习难度大。 其中进程概念是一个大难点, 里面知识点多, 晦涩难懂, 博主足足讲解了9篇,并且文章很长。 而进程控制有了前面进程概念的基础, 在理解起来就相对轻松一些, 并且内容较少, 论述性文字可能少一些, 博主通过包括本篇在内的3篇文章就可以完成讲解。 总之, 进程很重要, 希望友友们耐心学习。下面, 进入本节的学习吧。

        ps:本节适合了解进程概念, 以及进程的创建, 退出, 终止和等待的友友们进行观看。

目录

 什么是进程替换

单进程的进程替换

进程替换的原理

​编辑多进程的程序替换

 程序替换有没有创建新的进程

CPU是如何获取程序的入口地址的

详解exec接口

execl

execlp

execv

exec加载器

exec执行用户写的程序——含execle讲解

putenv

execle


 什么是进程替换

linux下有一种接口可以进行进程替换工作——exec

使用man手册, 然后就可以观察到详细内容:

上面的这些接口, 他们的工作都是一样的——把一个文件(可执行程序)替换程当前进程。 

单进程的进程替换

我们先以单进程, 也就是没有创建子进程为例, 来使用一下, 试验一下进程替换函数——exec, 我们这里使用的是execl函数, 因为它是最简单的一个进程替换函数。 

execl的参数是可变参数, 最后一个参数一定是NULL。如下图:

运行结果如下:

运行后我们就发现我们自己写的程序竟然能够将系统命令封装起来进行执行——这个过程, 就叫做程序替换。 而程序替换的现象就是把别人的程序替换一下, 在执行替换函数的之前逻辑的代码会跑,但是之后逻辑的代码就不会跑了。

进程替换的原理

        程序替换我们从上面的实验就能看到, 其实就是调用一下系统里面的其他程序, 生成一个新的进程。这个新的进程会生成一个PCB。

        首先, 会生成如下图:

        然后调用ls, 那么就会又将ls的代码数据加载到物理内存, 拷贝一份PCB、虚拟地址空间和页表。 ——这是我们以前对于创建子进程的理解。 但是对于execl, execl执行的程序不会执行上面的操作。而是直接将execl里面的程序的代码替换给物理内存里面原本进程加载的位置。 ——这, 就是程序替换。 

多进程的程序替换

然后再看一下多进程的程序替换是什么样子的。 多进程的程序替换, 我们就是要创建一个子进程,然后再执行一次程序替换。 现在我们就来实验一下:

        首先, 创建一个父进程:

然后, 根据父进程, 创建, 拷贝出子进程。 

        然后程序替换子进程:

在没有运行程序前, 什么都不会打印。

开始运行程序后, 父子进程都会被打印。 

5秒后子进程被替换, 执行ls。 同时执行完毕被等待, 资源被回收, 我们就能看到只会打印父进程了!!

 程序替换有没有创建新的进程

        刚开始运行的时候, 父子进程的PID一直没有变。 我们知道, 创建新进程需要创建新的PCB和地址空间以及页表。 然后拷贝所有的数据, 当涉及物理内存的修改时发生写时拷贝。 而父子进程的PID没有变, 也就是说, 程序替换不创建新进程, 只进行进程的代码和数据的替换工作!!

        那么, 为什么execl之后的代码没有被执行呢? 因为对于execl之后的代码来说, 这些代码的本质上也是属于原本的进程的。 但是当这个execl被执行, 这个进程的代码和数据就被替换了。 原本的代码和数据当然就没有用了!!

CPU是如何获取程序的入口地址的

        我们的CPU是如何获取程序的入口地址的呢? 这是因为, linux中形成的可执行程序, 是有格式的——ELF。 也就是可执行程序的表头, 这个表描述了可执行程序的段, 比如代码段, 数据段等等。 同时也有一个可执行程序的入口地址。 

详解exec接口

        现在重新看一下这些exec接口

execl

现在看博主写的这个程序:

        上面的程序调用了execl。 首先我们思考一下, 执行一个程序的第一件事是什么? 是不是要找到这个程序?所以, execl函数里面的第一个参数就是一个路径,是我们要执行的程序的绝对路径(相对路径也可, 但是执行命令的地方会被限制)。然后找到这个程序后, 我们是不是还要看看执行什么选项? 要以什么方式打开这个程序? 所以, 第二个参数以后的参数, 都是一些选项, 并且这些选项的最后一个必须是NULL, 就相当于一个链表。 链表里面存的是这些选项!!!为了区分表尾, 就必须把最后一个选项弄成NULL。

execlp

这个函数名比execl多了一个p, 这个p就叫做PATH路径。 代表execlp自己会在默认的PATH环境变量中查找。 ——也就是说, 我们传参时不需要传路径。 只需要传执行的文件名就行了!

就比如下图:

而之所以还要加上ls, 是因为PATH中只有路径, 没有文件名。

        PATH中的路劲, 加上ls文件名。 就能解决第一个——如何找到这个程序的问题。 

execv

        现在看一下execv, v就是数组, 第一个参数还是路径加文件名。 大师第二个参数是一个字符串指针数组。 

        这个数组就是将原本的ls -al变成ls, -a, -l。 这三个字符串分别作为字符串元素让这个指针数组指向他们。

下面是实验代码:

exec加载器

        那么, 现在问题来了。 请问ls是程序吗? 是程序, 那么是程序, ls就有main, 是不是也有命令行参数? 有了命令行参数, ls的命令行参数是从哪里来的呢? ——是从execv系统调用, 或者execl, execlp里面的参数里面获得的。 execl系列函数作为系统调用, 会把第二个参数的选项作为命令行参数传给第一个参数指向的可执行性程序。 

        在linux中, 所有进程都是别人的子进程, 在命令行当中, 所有的进程都是bash子进程。 所以, 所有进程在启动的时候, 都是使用exec系列函数启动执行的。 程序替换的本质就是将要替换的进程的数据和代码加载到内存当中。 所以, exec系列函数起到的就是加载器的效果。 

exec执行用户写的程序——含execle讲解

现在我们创建一个程序, 让我们原本的程序去调用这个程序:

ps:注意, 在c++当中的后缀可以是cpp, cxx, cc

利用makefile一次创建两个可执行程序,需要使用PHONY, 如下:

然后就会生成下面两个文件:

现在我们写一个程序调用otherExe.exe

运行后, 我们执行process-7-11.exe其实就是执行了otherExe.exe

 也可以调用脚本语言, 我们先创建一个shell脚本:

运行结果如下:

由上面两个例子我们就可以知道:语言和语言之间可以替换, 无论是我们的可执行程序, 还是脚本。 那么为什么能够跨语言调用呢?

其实所有语言运行起来, 本质上都是进程!!!

execl根本不是运行语言, 而是运行的进程, 只要是进程, 那么就可以被调用。 ——也就是说, 所有的语言, 只要最终可以变成进程, 那么最终都可以使用C/C++调用!!!

那么, 现在看一下命令行参数:我们将命令行参数传给myargv:

然后命令行参数就可以被打印出来:

我们也可以打印环境变量:

 

部分的打印结果如下:

         那么, 环境变量是什么时候给进程的呢? 环境变量也是数据, 当我们创建子进程的时候, 黄金变量就已经被子进程继承下去!!!

        所以, 我们即便没有传递命令行参数, 也是可以的!!!extern char** environ, 在进程定义的时候已经被父进程初始化了。 只要我们不写, 那么最终就是父进程的环境变量表!!!

        也就是说, 只要我们不写, 那么就是一张环境变量表。

        所以, 程序替换的时候, 环境变量的信息, 不会被替换。 所有如果我们相隔i紫禁城传递环境变量, 能怎么传递?

  • 第一种方式是新增环境变量——使用putenv在父进程中创建环境变量让子进程继承。
  • 第二种方式是彻底替换环境变量——使用execle替换

putenv

        我们先创建一个环境变量

        运行后, 我们的程序也有了这个环境变量:

        putenv的使用方法:putenv(“环境变量=数值") 在当前进程下创建一个环境变量并继承下去。

        在当前进程创建环境变量, 不会影响bash进程。

 

execle

传环境变量:带e的execl

 execle的参数如下:

 运行后就是下图: 可以看到运行结果里面也有MYNEWENV=666

 我们自定义这一张环境变量表

然后打印出来就是如下, 只会打印出我们自己定义的环境变量,  不会打印系统默认的环境变量。

自定义环境变量表, 采用的是覆盖, 而不是追加, 这就是彻底替换环境变量。

以上, 就是本届的全部内容, 下面是博主整理的本节的笔记:

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

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

相关文章

【IEEE出版】第五届大数据、人工智能与软件工程国际研讨会(ICBASE 2024,9月20-22)

第五届大数据、人工智能与软件工程国际研讨会(ICBASE 2024)将于2024年09月20-22日在中国温州隆重举行。 会议主要围绕大数据、人工智能与软件工程等研究领域展开讨论。会议旨在为从事大数据、人工智能与软件工程研究的专家学者、工程技术人员、技术研发人…

C#加班统计次数

C#加班统计次数 运行环境:vs2022 .net 8.0 社区版 1、用C#语言;2、有界面上传Excel文件; 3、对Excel列(部门、人员姓名、人员编号、考勤时间 )处理:(1)按人员编号、考勤日期分组且保留原来字段&…

大厂linux面试题攻略五之数据库管理

一、数据库管理-MySQL语句 0.MySQL基本语句: 1.SQL语句-增 创建xxx用户: mysql>create user xxx % indentified by 123456; xxx表示用户名 %b表示该用户用来连接数据库的方式(远程或本地连接) indentified by 123456设置密码…

C语言基础知识之函数指针和指针函数

函数指针和指针函数 函数指针和指针函数指向函数的指针返回指针值的函数指针函数和函数指针的区别 问题1_1代码1_1结果1_1 函数指针和指针函数 指向函数的指针 用函数指针变量调用函数 可以用指针变量指向整型变量、字符串、数组,也可以指向一个函数。一个…

Xinstall超级渠道功能,轻松解决App推广中的层级统计难题

随着互联网的不断发展和流量玩法的多样化,App推广和运营面临着前所未有的挑战。传统的营销方式在互联网流量红利衰退的背景下逐渐失效,企业急需提高获客转化的效率和用户留存。在这个过程中,App渠道数据分析显得尤为重要。然而,许…

Spring中是如何实现IoC和DI的?

前言:在前一篇文章中对于IoC的核心思想进行了讲解,而本篇文章则从Spring的角度入手,体会Spring对于IoC是如何实现的。 如果对IoC还有不太了解的可以阅读上一篇文章,相信一定会带来全新的收获:什么是IoC(控制…

J029_UDP通信

一、需求描述 实现UDP的通信 1.1 一发一收 1.1.1 ClientTest1 package com.itheima.udp;import java.net.*;import static java.net.InetAddress.*;//完成udp通信快速入门,实现一收一发 public class ClientTest1 {public static void main(String[] args) thro…

【数据结构之单链表的实现(不带头)】

1.单链表 1.1概念与结构 链表是一种物理存储结构上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。 可以用下图便于理解 节(结)点: 与顺序表不同的是,链表里面的每节“车…

NRK3301识别语音芯片在智能按摩椅中的应用与体验提升

在健康与舒适日益受到关注的今天,按摩椅作为缓解疲劳、舒缓压力的设备受到了广大消费者的喜爱。然而,传统的按摩椅操作方式往往繁琐且不直观。在这一背景下,NRK3301语音识别芯片的应用为按摩椅带来了新的变革。‌ 一、高识别准确率和快速响应…

halcon深度学习语义分割预处理图片遇到的坑

1.最近使用halcon深度学习语义分割,做缺陷检测。 2.在使用halcon的深度学习标准工具,标注图片 3.标注好图片后,到处预处理,发现报错,[‘Multiple matching segmentation files for image /1.jpg’]意思是:[’ image /…

二十天刷leetcode【hot100】算法- day1[前端Typescript]

哈希表 1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你…

go语言day21 goland使用gin框架、gorm框架操作mysql数据库redis数据库 使用宝塔创建redis数据库

GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly. gorm package - github.com/jinzhu/gorm - Go Packages go语言day20实现投票功能项目包-CSDN博客 gin框架标准项目结构: models:存放对应实体类和gorm包增删…

DVWA(SQL注入)medium、high

medium (1)判断注入是字符型还是数值型 数值型,获得了用户信息。 id 1 or 11 (2)查询字段数 为3时报错,代表字段数为2。 1 order by 3 (3)显示字段顺序 1 union select 1,2 &…

机器学习练手(三):基于决策树的iris 多分类和波士顿房价预测

总结:本文为和鲸python 可视化探索训练营资料整理而来,加入了自己的理解(by GPT4o) 原活动链接 原作者:vgbhfive,多年风控引擎研发及金融模型开发经验,现任某公司风控研发工程师,对…

【精通Redis】Redis事务

文章目录 前言一、标准事务1.1 标准事务的特性1.2 标准事务的生命周期1.3 事务的作用 二、Redis事务2.1 Redis事务的特性2.2 Redis事务与普通事务的区别 三、Redis事务常用命令总结 前言 我们在使用Redis的时候,有时为了处理多个结构,需要向Redis中一次…

Linux系统窗口水印难点分析

给应用程序加水印是保护数据的一种方式,window上可以通过给进程通过注入的方法给进程的窗口创建一个同大小的副窗口,在副窗口上绘制水印内容,同时设置副窗口透明同时透传事件,这样就可以达到在源窗口上显示水印的效果且不影响程序…

深⼊理解指针(3)

1. 字符指针变量 2. 数组指针变量 3. ⼆维数组传参的本质 4. 函数指针变量 5. 函数指针数组 6. 转移表 1. 字符指针变量 在指针的类型中我们知道有⼀种指针类型为字符指针 ⼀般使⽤: char* 这两种方式都是把字符串中的首字符的地址赋值给pc。 在这串代码中 str1内容的地…

ArkTS通用属性

目录 一、尺寸设置 宽高,外边距,内边距,尺寸size layoutWeight constraintSize 二、位置设置 align direction position offset 使用Edge方式position,offset 三、布局约束 aspectRatio displayPriority 四、Flex布局 flexBas…

RabbitMQ高级篇(如何保证消息的可靠性、如何确保业务的幂等性、延迟消息的概念、延迟消息的应用)

文章目录 1. 消息丢失的情况2. 生产者的可靠性2.1 生产者重连2.2 生产者确认2.3 生产者确认机制的代码实现2.4 如何看待和处理生产者的确认信息 3. 消息代理(RabbitMQ)的可靠性3.1 数据持久化3.2 LazyQueue( 3.12 版本后所有队列都是 Lazy Qu…