【C++探索学习】第十九弹——进程替换:深入解析操作系统中的进程替换机制

Linux学习笔记:

https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482

前言:

在Linux操作系统中,进程替换(Process Replacement)是一个重要的概念,它允许程序通过系统调用用另一个程序替换当前进程的执行内容。这个操作通常是通过exec系列系统调用实现的。进程替换使得一个进程可以在不改变进程ID(PID)的情况下,执行不同的程序。理解和掌握exec系列函数对于深入了解Linux进程管理、进程间通信和系统编程非常重要。

本文将详细讲解Linux中进程替换的概念、exec系列函数的使用方法、相关的系统调用、常见的用法示例,以及进程替换的实际应用场景。同时还会提供丰富的代码示例,帮助大家更好地理解这些函数的使用。

目录

1. 什么是进程替换?

进程替换的核心特点:

2. exec系列函数

2.1 execve() 函数

函数原型:

示例代码:使用 execve() 执行一个程序

2.2 execvp() 函数

函数原型:

示例代码:使用 execvp() 执行一个程序

2.3 execlp() 函数

函数原型:

示例代码:使用 execlp() 执行一个程序

2.4 execv() 函数

函数原型:

示例代码:使用 execv() 执行一个程序

2.5 execl() 函数

函数原型:

示例代码:使用 execl() 执行一个程序

3. exec系列函数的常见错误

3.1 返回值与错误处理

3.2 exec的限制

4. 总结


1. 什么是进程替换?

在Linux中,进程替换是指一个进程通过调用exec系列函数来替换其当前的代码、数据、堆栈等内存区域,进而加载并执行新的程序。换句话说,进程替换使得一个正在运行的进程不再执行原来的程序,而是执行另一个程序。

进程替换发生时,当前进程的内存空间会被新的程序映像所替换。需要注意的是,进程替换操作本身并不会改变进程的PID(进程ID)。也就是说,进程替换发生后,新的程序在执行时,进程ID仍然是原进程的PID。(结合我们之前所讲的内容,进程替换改变的不是进程本身,而是页表对应的物理地址)

进程替换的核心特点:

  • 内存空间替换:进程的内存(代码段、数据段、堆栈等)会被新的程序映像替换。
  • 进程ID不变:即使进程的执行内容发生了变化,进程的PID不会改变。
  • 文件描述符继承:除非显式关闭,进程的文件描述符会被继承到新程序中,并且它们的状态(如文件指针位置)也会被继承。

这里内存空间替换更深层的其实是连接虚拟地址和物理地址之间页表指向的改变,关于页表的内容我们在前面讲进程地址空间时有讲过,作为拔高内容了解即可

进程替换通常与fork系统调用结合使用。在使用fork时,父进程会创建一个子进程,子进程继承父进程的状态(包括文件描述符、内存、环境变量等)。接着,子进程通过exec系列函数来替换自身的程序内容,执行新的任务。

2. exec系列函数

在Linux中,exec系列函数用于执行进程替换。它们会用新的程序替换当前进程的映像。exec系列函数有多个变种,常用的包括:

  • execve():最基础的系统调用,提供程序路径、参数数组和环境变量列表。
  • execvp():根据$PATH环境变量查找程序路径并执行。
  • execlp():与execvp()类似,但以参数列表的形式提供命令行参数。
  • execv():与execve()类似,但不查找$PATH,需要提供完整的程序路径。
  • execl():与execlp()类似,但以参数列表的形式传递命令行参数。

我们可以通过man函数手册来查看:

man exec

2.1 execve() 函数

execve()exec系列函数中最基础的函数,也是其他exec函数的底层实现。它允许一个进程加载并执行指定路径的程序,同时传递命令行参数和环境变量。

函数原型:
int execve(const char *pathname, char *const argv[], char *const envp[]);
  • pathname:要执行的程序的完整路径。
  • argv:一个字符串数组,包含传递给程序的命令行参数,最后必须以NULL结尾。
  • envp:一个字符串数组,包含程序的环境变量,最后也必须以NULL结尾。
示例代码:使用 execve() 执行一个程序
#include <stdio.h>
#include <unistd.h>int main() {char *args[] = {"ls", "-l", NULL};  // 命令行参数char *env[] = {"PATH=/bin", NULL};  // 环境变量printf("Before execve\n");if (execve("/bin/ls", args, env) == -1) {perror("execve failed");}printf("This will not be printed if execve is successful.\n");return 0;
}

在这个示例中,execve()会替换当前进程并执行ls -l命令。execve()调用成功后,原来的进程中的内容就会被替换,所以后续的printf语句将不会执行。

2.2 execvp() 函数

execvp()execve()的一个更高层的封装。它根据环境变量$PATH来查找可执行文件并执行。这意味着你只需要指定可执行文件的名称,而无需提供完整的路径。

函数原型:
int execvp(const char *file, char *const argv[]);
  • file:要执行的程序的名称,系统会根据$PATH查找该程序。
  • argv:命令行参数数组,最后必须以NULL结尾。
示例代码:使用 execvp() 执行一个程序
#include <stdio.h>
#include <unistd.h>int main() {char *args[] = {"ls", "-l", NULL};  // 命令行参数printf("Before execvp\n");// 使用 $PATH 查找可执行文件并执行execvp("ls", args);printf("This will not be printed if execvp is successful.\n");return 0;
}

在这个示例中,execvp()会根据$PATH查找ls命令并执行。如果execvp()调用成功,后续的printf语句将不会执行。

2.3 execlp() 函数

execlp()execvp()的一个变种,它允许你直接传递命令行参数,而不需要构建一个参数数组。

函数原型:
int execlp(const char *file, const char *arg, ...);
  • file:要执行的程序的名称,系统会根据$PATH查找该程序。
  • arg:程序的第一个参数,紧跟着是程序的其他参数,最后一个参数必须是NULL
示例代码:使用 execlp() 执行一个程序
#include <stdio.h>
#include <unistd.h>int main() {printf("Before execlp\n");// 使用 $PATH 查找可执行文件并执行execlp("ls", "ls", "-l", NULL);printf("This will not be printed if execlp is successful.\n");return 0;
}

在这个示例中,execlp()会查找ls命令并执行。与execvp()不同,execlp()是通过可变参数来传递命令行参数的,而不是使用数组。

运行结果:

2.4 execv() 函数

execv()execve()的一个封装,允许你提供程序路径和参数数组。它不通过$PATH查找程序,而是需要提供完整的程序路径。

函数原型:
int execv(const char *pathname, char *const argv[]);
  • pathname:要执行的程序的完整路径。
  • argv:命令行参数数组,最后必须以NULL结尾。
示例代码:使用 execv() 执行一个程序
#include <stdio.h>
#include <unistd.h>int main() {char *args[] = {"ls", "-l", NULL};  // 命令行参数printf("Before execv\n");// 使用完整路径执行命令execv("/bin/ls", args);printf("This will not be printed if execv is successful.\n");return 0;
}

在这个示例中,execv()会用完整路径/bin/ls来执行命令。如果execv()调用成功,后续的printf语句将不会执行。

运行结果:

2.5 execl() 函数

execl()execlp()的一个变种,使用可变参数的方式来传递命令行参数。

函数原型:
int execl(const char *pathname, const char *arg, ...);
  • pathname:要执行的程序的完整路径。
  • arg:程序的第一个参数,后面是其他参数,最后一个参数必须是NULL
示例代码:使用 execl() 执行一个程序
#include <stdio.h>
#include <unistd.h>int main() {printf("Before execl\n");// 执行命令并传递参数execl("/bin/ls", "ls", "-l", NULL);printf("This will not be printed if execl is successful.\n");return 0;
}

在这个示例中,execl()会执行/bin/ls命令,并传递参数-l

运行结果:

3. exec系列函数的常见错误

尽管exec系列函数非常强大,但它们也有一些常见的错误,需要注意。

3.1 返回值与错误处理

exec系列函数调用成功时,不会返回控制权给调用者。它们会替换当前进程的映像,新的程序开始执行。因此,如果exec调用成功,后面的代码将不会执行。如果调用失败,exec函数会返回-1,并设置errno,你可以通过perror()strerror()函数来输出错误信息。

常见的错误包括:

  • ENOENT:文件不存在。指定的可执行文件无法找到。
  • EACCES:权限不足。没有足够的权限来执行指定的文件。
  • ENOMEM:内存不足。系统无法为新的程序分配足够的内存。

3.2 exec的限制

  • exec替换时会丢失进程的原始状态。当前进程的栈、堆、全局变量等都会被新的程序内容覆盖。如果你需要保存某些状态(如打开的文件描述符),应在调用exec前进行适当的保存。
  • exec不会返回,如果你需要在exec失败时处理错误,必须在调用后检查返回值。

4. 总结

进程替换是Linux中一个非常重要的概念,exec系列函数提供了在运行时替换当前进程的能力。通过execve()execvp()execlp()execv()execl()等函数,我们可以灵活地执行不同的程序,而不需要创建新的进程。

进程替换通常与fork结合使用,fork创建一个新进程,而exec替换子进程的程序映像。这种模式广泛应用于Shell的实现、任务调度、进程间通信等领域。

函数描述
execve执行指定路径的程序,传递命令行参数和环境变量。
execvp根据$PATH查找可执行文件并执行,传递参数。
execlpexecvp类似,但以参数列表的形式传递命令行参数。
execvexecve类似,但不查找$PATH,需要提供完整路径。
execlexeclp类似,但以参数列表的形式传递命令行参数。

理解并熟练使用exec系列函数,是编写高效、灵活的系统程序的关键之一。希望本文通过丰富的代码示例和详细的解释,能够帮助你更好地掌握Linux中的进程替换机制。

本篇笔记:


感谢各位大佬观看,创作不易,还望各位大佬点赞支持!!!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[软件工程]八.软件演化

8.1什么是软件演化 由于种种不可避免的原因&#xff0c;系统开发完成后的软件需要进行修改来适应变更的需求&#xff0c;我们对软件的修改就叫软件演化。 8.2为什么软件会演化 由于业务的变更或者为了满足用户期待的改变&#xff0c;使得对已有的系统的新需求浮现出来。由于…

WiFi受限不再愁,电脑无网络快速修复指南

有时在试图连接WiFi时&#xff0c;会发现网络连接受限&#xff0c;或无法正常访问互联网。这种情况不仅影响了工作效率&#xff0c;还可能错过重要的信息。那么&#xff0c;究竟是什么原因导致了电脑WiFi连接受限呢&#xff1f;又该如何解决这一问题呢&#xff1f;小A今天就来教…

【Liunx篇】基础开发工具 - yum

文章目录 &#x1f335;一.Liunx下安装软件的方案&#x1f43e;1.源代码安装&#x1f43e;2.rpm包安装&#x1f43e;3.包管理器进行安装 &#x1f335;二.软件包管理器-yum&#x1f335;三.yum的具体操作&#x1f43e;1.查看软件包&#x1f43e;2.安装软件包&#x1f43e;3.卸载…

第七节(2)、T型加减速优化处理【51单片机-TB6600驱动器-步进电机教程】

摘要&#xff1a;本节介绍解决标准T型加减速过程中的两个缺陷&#xff0c;其一是使得初速度任意设置&#xff1b;其二是降低Cn递推计算量&#xff0c;提升速度上限 一. 加速减速过程计算 1.1计算不存在匀速过程 根据基本运动定理&#xff1a; w m a x w 0 a 0 ∗ t n 0 … …

什么是继承性?C++中如何实现继承? 继承的好处和注意事项有哪些?

1) 什么是继承性&#xff1f;C中如何实现继承&#xff1f; 一、继承性的概念 继承性是面向对象编程中的一个重要特性&#xff0c;它允许一个类&#xff08;称为子类或派生类&#xff09;继承另一个类&#xff08;称为父类或基类&#xff09;的属性和方法。继承的主要目的是实现…

唇形同步视频生成工具:Wav2Lip

一、模型介绍 今天介绍一个唇形同步的工具-Wav2Lip&#xff1b;Wav2Lip是一种用于生成唇形同步&#xff08;lip-sync&#xff09;视频的深度学习算法&#xff0c;它能够根据输入的音频流自动为给定的人脸视频添加准确的口型动作。 &#xff08;Paper&#xff09; Wav2Lip模型…

ESP32使用TCA9548A IIC多路复用器拓展

ESP32使用TCA9548A IIC多路复用器拓展 本文将讲述如何使用TCA9458A IIC多路复用器扩展IIC总线端口。使用相同的IIC地址控制多个IIC设备&#xff0c;如多个OLED或BME280等 TCA9548介绍 IIC通信协可以实现在同一IIC总线上与多个IIC设备通信&#xff0c;只要所有设备都具有唯一…

BGP路径属性与路由反射器

BGP路径属性 路径属性&#xff1a; 任何一条BGP路由都拥有多个路径属性 当路由器将BGP路由通告给它的对等体时&#xff0c;一并被通告的还有路由所携带的各各路径属性 BGP的路径属性将影响路由优选 路径四个属性分类&#xff1a; 公认必遵&#xff1a;必须包括在每个upda…

C语言期末考试——重点考点

目录 1.C语言的结构 2.三种循环结构 3.逻辑真假判断 4. printf函数 5. 强制类型转化 6. 多分支选择结构 7. 标识符的定义 8. 三目运算符 1.C语言的结构 选择结构、顺序结构、循环结构 2.三种循环结构 for、while、do-while 3.逻辑真假判断 C语言用0表示false,用非0(不…

ci/cd配置任务超时时间

有两个地方决定了任务超时时间&#xff1a; 1. 2.gitlab-runner

JUC:Synchronized和锁升级

1. 面试题 谈谈你对Synchronized的理解Sychronized的锁升级你聊聊Synchronized实现原理&#xff0c;monitor对象什么时候生成的&#xff1f;知道monitor的monitorenter和monitorexit这两个是怎么保证同步的嘛&#xff1f;或者说这两个操作计算机底层是如何执行的偏向锁和轻量级…

梯度下降法以及 Python 实现

文章目录 1. 引言2. 梯度法3. 例子4. 代码实现5. 讨论 — 学习率 η \eta η5.1 当 η \eta η 设置过大5.2 当 η \eta η 设置过小 参考 1. 引言 梯度下降法&#xff0c;可以根据微分求出的斜率计算函数的最小值。 在人工智能中&#xff0c;经常被应用于学习算法。 2. 梯…

OpenCV-图像阈值

简单阈值法 此方法是直截了当的。如果像素值大于阈值&#xff0c;则会被赋为一个值&#xff08;可能为白色&#xff09;&#xff0c;否则会赋为另一个值&#xff08;可能为黑色&#xff09;。使用的函数是 cv.threshold。第一个参数是源图像&#xff0c;它应该是灰度图像。第二…

详细了解IO分类

按照数据流方向如何划分&#xff1f; 输入流&#xff08;Input Stream&#xff09;&#xff1a;从源&#xff08;如文件、网络等&#xff09;读取数据到程序。 输出流&#xff08;Output Stream&#xff09;&#xff1a;将数据从程序写出到目的地&#xff08;如文件、网络、控…

Appium 安装问题汇总

好生气好生气&#xff0c;装了几天了&#xff0c; opencv4nodejs 和 mjpeg-consumer 就是装不了&#xff0c;气死我了不管了&#xff0c;等后面会装的时候再来完善&#xff0c;气死了气死了。 目录 前言 1、apkanalyzer.bat 2、opencv4nodejs 3、ffmpeg 4、mjpeg-consume…

目标检测知识点总结

1、数据增强 2、指标 3、vit 、swint ViT算法&#xff0c;创新性地将图像划分成一个个patch&#xff0c;并将每个patch展平为一个向量&#xff0c;使得图像数据转化为序列化数据&#xff0c;之后输入到Transformer模型中&#xff0c;实现了Transformer在图像分类任务中的应用。…

Lecture 11 - List,Set,Map

List, Set and Map are all interfaces: they define how these respective types work, but they don’t provide implementation code overview 1. List&#xff08;列表&#xff09;&#xff1a; &#xff08;1&#xff09; 创建、访问和操作列表&#xff1a;ArrayList …

ElfBoard开源项目|基于百度智能云平台的车牌识别项目

本项目基于百度智能云平台&#xff0c;旨在利用其强大的OCR服务实现车牌号码的自动识别。选择百度智能云的原因是其高效的API接口和稳定的服务质量&#xff0c;能够帮助开发者快速实现车牌识别应用。 本项目使用摄像头捕捉图像后&#xff0c;通过集成百度OCR服务的API&#xf…

应对超声波测试挑战,如何选择合适的数字化仪?

一、数字化仪的超声波应用 超声波是频率大于人类听觉范围上限的声学声压&#xff08;声学&#xff09;波。超声波设备的工作频率为20 kHz至几千MHz。表1总结了一些更常见的超声波应用的特征。 每个应用中使用的频率范围都反映了实际情况下的平衡。提高工作频率可以通过提高分…

product/admin/list?page=0size=10field=jancodevalue=4562249292272

文章目录 1、ProductController2、AdminCommonService3、ProductApiService4、ProductCommonService5、ProductSqlService https://api.crossbiog.com/product/admin/list?page0&size10&fieldjancode&value45622492922721、ProductController GetMapping("ad…