Linux:进程控制(二.详细讲解进程程序替换)

上次讲了:Linux:进程地址空间、进程控制(一.进程创建、进程终止、进程等待)


文章目录

  • 1.进程程序替换
    • 1.1概念
    • 1.2原理
    • 1.3使用一个`exec` 系列函数
      • execl()函数
      • 结论与细节
  • 2.多进程时的程序替换
  • 3.其他几个exec系列函数
    • 也可以调用其他语言的程序
      • 想要生成两个可执行文件的makefile


1.进程程序替换

之前我们进行的程序演示里,都只能运行自己的代码。那我们怎么样才能执行其他程序的代码呢?(例如在程序里使用ls之类的指令)就可以使用进程程序替换,一开始我们先只看单进程的情况。后面在引入多进程的情况

1.1概念

进程程序替换是指在运行过程中将一个进程的地址空间中的代码、数据和堆栈等内容完全替换为另一个程序的代码、数据和堆栈的过程。这个过程通常是由操作系统提供的 exec 系列函数来实现的:

  • 地址空间替换:进程的地址空间是指进程可以访问的内存范围。通过地址空间替换,进程可以在运行时动态地加载并执行不同的程序,从而实现灵活的程序执行和管理。

  • exec 函数族exec 函数族是一组系统调用,用于执行程序替换操作。这些函数包括 execl, execv, execle, execve 等,它们允许以不同的方式传递参数给新程序,并执行地址空间替换。

    我们要改变内存,那肯定是要调用系统调用接口的,这些函数会封装相应的接口

  • 程序入口点:新程序的入口点是程序中的起始执行位置,通常是 main 函数或其他指定的入口函数。替换完成后,控制权将转移到程序入口点,开始执行新程序的代码。

1.2原理

  • 当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换
  • 替换完成后,控制权将转移到新程序的入口点,开始执行新程序的代码。

在这里插入图片描述

1.3使用一个exec 系列函数

execl()函数

execl函数是Linux系统中用于执行新程序的函数之一,它属于exec函数族的一部分。这个函数的作用是在当前进程的上下文中启动一个新的程序,并替换当前进程的映像为新的程序映像。调用execl函数后,当前进程将停止执行,并由新的程序开始执行

#include<unistd.h>
int execl(const char *path, const char *arg0, ... /* (char  *) NULL */);

参数说明:

  • path:要执行的程序的路径。
  • arg0:新程序的参数列表的开始,通常这会是新程序的名称(尽管这不是强制的,但它通常用于错误消息和程序内部)。
  • ...:一个可变参数列表(参数的数量不固定),新程序的参数列表,必须以NULL结尾。

execl函数会根据提供的路径path找到并执行相应的程序,同时arg0及其后面的参数作为新程序的命令行参数传递。注意,参数列表必须以NULL结尾,这是告诉execl参数列表结束的标志。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{printf("I'm a process, pid: %d\n", getpid());printf("execl begin...\n");int a=execl("/usr/bin/ls", "ls", "-a", "-l", NULL);printf("execl end...\n");return 0;
}

在这里插入图片描述

如果execl函数调用成功,那么它实际上不会返回,因为当前进程的映像已经被新程序替换。如果调用失败,它会返回-1,并设置全局变量errno以指示错误原因。常见的错误原因可能包括文件未找到、权限不足等。

execl函数和其他exec函数一样,不会创建新的进程。它们只是在当前进程的上下文中启动另一个程序

因此,调用execl前后,进程的ID(PID)不会改变。同时,由于execl会替换整个进程映像,所以在调用execl之前,通常需要确保当前进程的所有打开的文件描述符、内存分配等都被适当地处理或释放,因为这些资源不会被新程序继承。

结论与细节

  1. 程序替换一旦成功,exec后面的代码不在执行。因为被替换掉了,这也是什么代码没有输出execl end的原因了

  2. exec函数调用成功,那么它实际上不会有返回值;调用失败,它会返回-1

  3. exec函数不会创建新的进程。它们只是在当前进程的上下文中启动另一个程序

  4. 创建一个进程。我们是先创建PCB、地址空间、页表等再先把程序加载到内存

    先加载的话,页表都没办法映射的

  5. 程序替换的本质就是加载 (可以看成一个加载器),有替换就是替换,没有就是程序加载

    程序替换的本质是程序加载,因为在执行 exec 函数时,操作系统会加载新程序的可执行文件,并将其代码、数据和堆栈等部分加载到进程的地址空间中。这个过程涉及将新程序的内容从磁盘加载到内存中,为进程提供执行所需的资源。因此,虽然我们常说是“程序替换”,但实际上更准确地说是将新程序加载到内存中,替换掉原有的程序,以实现进程的功能切换和更新。

  6. 程序运行要加载到内存;为什么?冯诺依曼体系规定;如何加载的呢?就是程序替换:程序替换是操作系统的接口,所谓的把磁盘里的数据加载到内存就是把磁盘设备的数据拷贝到内存里。把数据从一个硬件搬到另一个硬件,只有操作系统能做

2.多进程时的程序替换

我们可以创建一个子进程,由子进程来进行程序替换,父进程来等待结果就可以。为什么? 父进程能得到子进程的执行结果

我们知道父进程与子进程映射到同一块代码,那么子进程进行程序替换后,不是会覆盖吗,替换为什么不影响父进程?

进程具有独立性,在进行程序替换时要进行写时拷贝

写时拷贝的本质就是开辟新的空间

shell是如何运行起来一个指令的?

首先创建子进程,shell会waitpid()等待进程结果,子进程会继承shell的代码,但是不影响。子进程进行程序替换,替换为我们输入的指令

int main()
{pid_t id = fork();if (id == 0){printf("I'm a process, pid: %d\n", getpid());printf("execl begin...\n");execl("/usr/bin/ls", "ls", "-a", "-l", NULL);printf("execl end...\n");exit(1);}pid_t rid = waitpid(id, NULL, 0);if (rid > 0){printf("wait successfully\n");}return 0;
}

在这里插入图片描述

3.其他几个exec系列函数

在这里插入图片描述

  1. execl:该函数允许通过提供可变数量的参数来执行指定的可执行文件。它的原型如下:

    int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
    

    path 是要执行的可执行文件的路径,arg0 是第一个参数,后续参数都是传递给可执行文件的命令行参数,以 NULL 结尾。

  2. execlp:该函数与 execl 类似,但是它会在系统的环境变量 PATH 指定的目录中查找可执行文件。它的原型如下:

    int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
    

    file 是要执行的可执行文件的文件名arg0 是第一个参数,后续参数都是传递给可执行文件的命令行参数,以 NULL 结尾。

    相比于execl函数,execlp函数的第一个参数能直接写文件名,系统会PATH环境变量里去查找

    多的字母p:PATH环境变量

    int main()
    {pid_t id = fork();if (id == 0){printf("I'm a process, pid: %d\n", getpid());printf("execl begin...\n");execl("ls", "ls", "-a", "-l", NULL);printf("execl end...\n");exit(1);}pid_t rid = waitpid(id, NULL, 0);if (rid > 0){printf("wait successfully\n");}return 0;
    }
    

    在这里插入图片描述

  3. execv:类似于 execl,但是允许传递一个参数数组给被执行的程序。它的原型如下:

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

    path 是要执行的可执行文件的路径argv 是一个NULL 结尾的参数数组,其中每个元素都是一个字符串,表示命令行参数

    相比于exec多个字母v:代表vector

    int main()
    {pid_t id = fork();if (id == 0){printf("I'm a process, pid: %d\n", getpid());printf("execl begin...\n");char* argv[] = { "ls","-a","-l",NULL};execv("/usr/bin/ls",argv);printf("execl end...\n");exit(1);}pid_t rid = waitpid(id, NULL, 0);if (rid > 0){printf("wait successfully\n");}return 0;
    }
    

    在这里插入图片描述

  4. execvp:类似于 execv,但是它会在系统的环境变量 PATH 指定的目录中查找可执行文件。它的原型如下:

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

file 是要执行的可执行文件的文件名,argv 是一个以 NULL 结尾的参数数组,其中每个元素都是一个字符串,表示命令行参数。

既有字母p 又有v,结合上面那两种就行

  1. execle:函数与 execl 函数类似,但允许在启动新程序时传递额外的环境变量。它的原型如下:

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

    path 是要执行的可执行文件的路径,arg 是要传递给新程序的命令行参数,后面的参数是额外的环境变量,以 NULL 结尾。

进程程序替换不会替换环境变量的

  1. 想要子进程继承全部的环境变量,不用管,直接就能拿到

  2. 单纯新增环境变量,在父进程里使用putenv()函数,会影响子进程

putenv 是 C 语言中的一个库函数,它定义在 <stdlib.h> 头文件中。这个函数用于将字符串添加到环境变量中,或者修改已经存在的环境变量的值。

int putenv(const char *string);
  1. 使用全新的环境变量,就使用execle()函数,那么替换后的代码切换后的环境变量就只是我们传入的表里的内容

也可以调用其他语言的程序

code.c里:

int main()
{char* const env[] = {(char*)"first",(char*)"second",NULL };pid_t id = fork();if (id == 0){printf("I'm a process, pid: %d\n", getpid());printf("execl begin...\n");execle("./mytest", "mytest", NULL, env)printf("execl end...\n");exit(1);}pid_t rid = waitpid(id, NULL, 0);if (rid > 0){printf("wait successfully\n");}return 0;
}

test.cpp里:

#include <iostream>
#include <unistd.h>using namespace std;int main()
{for (int i = 0; environ[i]; i++){printf("env[%d]: %s\n", i, environ[i]);}cout << "This is C++" << endl;return 0;
}

image-20240416203229251

当然我们也能传系统环境变量,但是没必要,这样的话直接默认就行

execle("./mytest", "mytest", NULL, environ)//传入这个全局变量

想要生成两个可执行文件的makefile

.PHONY:all
all:mycode mytestmycode:code.cgcc -o $@ $^
mytest:test.cppg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -f mycode mytest
  1. .PHONY:声明一个或多个目标是伪目标(phony targets)通过声明伪目标,你可以确保 make 总是执行相应的命令,而不会因为同名的文件或目录的存在而跳过这些命令
  2. 运行 make 命令时(没有指定具体目标),make 会首先查找 Makefile 中的第一个目标,并尝试构建它。在这个过程中,make 会检查该目标的所有依赖项,并递归地处理这些依赖项,直到所有必要的依赖项都被构建或确认为是最新的
  3. make 工具被调用以构建某个目标时,它会检查该目标的所有依赖项,并根据需要构建这些依赖项。然而,对于 clean 这样的伪目标,它并没有列出任何依赖项,因此其他目标的构建状态不会影响 clean 的执行

今天就到这里啦,感谢大家支持

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

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

相关文章

mysql连接池的实现

概要&#xff1a;本文介绍mysql连接池的实现&#xff0c;要求读者了解线程池 一、为什么需要mysql连接池&#xff1f; 资源复用 &#xff1a;不使用连接池&#xff0c;每次数据库请求都新建一条连接&#xff0c;将耗费系 统资源。 流程如下&#xff1a; 通过三次握手建立 TC…

大数据面试题 —— Hive

目录 Hive 是什么为什么要使用 HiveHive 的优缺点Hive的实现逻辑&#xff0c;为什么处理小表延迟比较高你可以说一下 HQL 转换为 MR 的任务流程吗 ***你可以说一下 hive 的元数据保存在哪里吗 ***Hive与传统数据库之间的区别Hive内部表和外部表的区别 ***hive 动态分区与静态分…

Hotcoin Research | 市场洞察:2024年5月13日-5月19日

加密货币市场表现 目前&#xff0c;加密货币总市值为1.32万亿&#xff0c;BTC占比54.41%。 本周行情呈现震荡上行的态势&#xff0c;BTC在5月15日-16日&#xff0c;有一波大的拉升&#xff0c;周末为震荡行情。BTC现价为67125美元。 上涨的主要原因&#xff1a;美国4月CPI为3…

效率工作:一键为多种资产添加统一材质(小插件)

1.需求分析&#xff1a; 当导入一批资产&#xff0c;或者有同一批结构体需要添加相同材质时&#xff0c;单独为每个模型都添加材质费时费力&#xff0c;有没有什么办法&#xff0c;能同时为多个资产添加材质。 2.操作实现 1.在网上找到了一款插件&#xff0c;经过验证&#xf…

如何将天猫内容保存为PDF格式?详细步骤与实战解析

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;保存天猫内容的重要性 二、环境准备与工具安装 1. 安装必要的Python包…

SpringCloud之SSO单点登录-基于Gateway和OAuth2的跨系统统一认证和鉴权详解

单点登录&#xff08;SSO&#xff09;是一种身份验证过程&#xff0c;允许用户通过一次登录访问多个系统。本文将深入解析单点登录的原理&#xff0c;并详细介绍如何在Spring Cloud环境中实现单点登录。通过具体的架构图和代码示例&#xff0c;我们将展示SSO的工作机制和优势&a…

HCIP-Datacom-ARST自选题库__BGP多选【22道题】

1.BGP认证可以防止非法路由器与BGP路由器建立邻居&#xff0c;BGP认证可以分为MD5认证和Keychain认证&#xff0c;请问以下哪些BGP报文会携带BCGP Keychain认证信息?(报头携带) open Update Notication Keepalive 2.传统的BGP-4只能管理IPv4单播路由信息&#xff0c;MP-B…

Spring-Cloud-OpenFeign源码解析-04-调用流程分析

在Spring-Cloud-OpenFeign源码解析-03-FeignClientFactoryBean分析到&#xff0c;通过Autowired或者Resource注入FeignClient实例的时候&#xff0c;实际上返回的是JDK动态代理对象&#xff0c;具体的实现逻辑在InvocationHandler的invoke方法中 回看ReflectiveFeign.newInsta…

AI大模型日报#0528:Greg专访 | 为什么OpenAI最先做出GPT-4、xAI获60亿美元融资、李飞飞经典对话Hinton

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE 4.0&#xff09;、“零一万物”&#xff08;Yi-34B&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅读&#xff0…

YOLOv8/YOLOv7/YOLOv5+CRNN-车牌识别、车牌关键点定位、车牌检测(毕业设计)

目录 一、前言1、项目介绍2、图片测试效果展示 二、项目环境配置1、pytorch安装&#xff08;gpu版本和cpu版本的安装)2、pycocotools的安装3、其他包的安装 三、yolov8/yolov7/yolov5CRNN-中文车牌识别、车牌关键点定位、车牌检测算法1、yolov8算法介绍2、CRNN算法介绍3、算法流…

【加密与解密(第四版)】第十三章笔记

第十三章 HOOK技术 13.1 Hook概述 IAT HOOK&#xff08;改地址&#xff09; BOOL IAT_InstallHook(){BOOL bResult FALSE ;HMODULE hCurExe GetModuleHandle(NULL);PULONG_PTR pt ;ULONG_PTR OrginalAddr;bResult InstallModuleIATHook(hCurExe,"user32.dll",&qu…

韩顺平0基础学Java——第13天

p264-p284 安装IDEA&#xff0c;熟悉一下软件。 尴尬了&#xff0c;难道是这个版本的idea不支持jdk17&#xff0c;难受住了 成功了&#xff0c;顺便跑一下昨天的作业&#xff1a; 这都要跑2秒&#xff1f;是电脑的问题还是谁的问题&#xff1f;控制台里跑的好快的哦 设置id…

Thingsboard规则链:Message type switch节点详解

在物联网解决方案中&#xff0c;数据的高效处理与自动化决策流程是实现智能化管理的基础。Thingsboard&#xff0c;作为一个强大的开源物联网平台&#xff0c;通过其规则引擎为用户提供了一系列灵活的节点来定制复杂的业务逻辑。其中&#xff0c;Message Type Switch节点是构建…

BookxNote Pro 宝藏 PDF 笔记软件

一、简介 1、BookxNote Pro 是一款专为电子书阅读和学习笔记设计的软件&#xff0c;支持多种电子书格式&#xff0c;如PDF和EPUB&#xff0c;能够帮助用户高效地管理和阅读电子书籍&#xff0c;同时具备强大的笔记功能&#xff0c;允许用户对书籍内容进行标注、摘录和思维导图绘…

Springboot启动时报错Property ‘mapperLocations‘ was not specified.

这几天没整boot 晚上直接运行不了了 本想是在表现层写点代码测测接口的 localhost8080找半天 结果404 先考虑好久 是不是url输入错了 然后 就发现 结果boot都不能启动了 JUnit也测不出来 找了半天 结果是开关机导致数据库没开 手动打开服务 找到MySQL启动 IDEA连接数据…

ssm/springoot养老院问诊服务预约系统_96316老年人服务系统

2.管理员&#xff1a; &#xff08;1&#xff09;登入注册页面&#xff1a;管理员进行操作时需要是已注册登入的 &#xff08;2&#xff09;权限管理&#xff1a;管理员登入后可以运用权限进行相应的操作管理。 &#xff08;3&#xff09;用户管理&#xff1a;对用户进行删除、…

国产数据库替代加速 助力数字中国建设

5月24日&#xff0c;随着第七届数字中国建设峰会在福州的成功举办&#xff0c;释放数据要素价值、发展新质生产力成为当下热议的话题。 数据作为新型生产要素&#xff0c;是数字化、网络化、智能化的重要基础。北京人大金仓信息技术股份有限公司&#xff08;以下简称人大金仓&a…

OpenHarmony实战开发——宿舍全屋智能开发指南

项目说明 基于OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;、数字管家开发宿舍全屋智能&#xff0c;实现碰一碰开门、碰一碰开灯、碰一碰开风扇以及烟感检测。因为各项目开发流程大体相似&#xff0c;本文主要以碰一碰开门为例介绍如何在现有OpenHar…

西储大学数据集学习

数据集下载地址&#xff1a;CWRU凯斯西储大学轴承数据数据集——附&#xff1a;下载链接_西储大学轴承数据集下载-CSDN博客 最近研究故障诊断&#xff0c;先对使用比较多的西储大学数据集研究。以资料【1】中的内容展开研究。 1、轴承的结构 轴承分为外圈、内圈、保持架和滚珠…

CC工具箱使用指南:【Word特定文本批量替换(BHM)】

一、简介 群友定制工具。 工具所要做的是批量更新Word模板中的特定文本。 输入参数为一个Word模板和Excel更新数据。 Word模板长这样&#xff1a; Word中需要更新的文本都用大括号及里内部的标签标注出来。 对应的Excel长这样&#xff1a; 第一行的标签和Word里的一一对应…