Linux--进程的程序替换

问题导入:

前面我们知道了,fork之后,子进程会继承父进程的代码和“数据”(写实拷贝)。

那么如果我们需要子进程完全去完成一个自己的程序怎么办呢?

进程的程序替换来完成这个功能!

1.替换原理

⽤fork创建⼦进程后执⾏的是和⽗进程相同的程序(但有可能执⾏不同的代码分⽀),⼦进程往往要调⽤⼀种 exec函数 以执⾏另⼀个程序。当进程调⽤⼀种exec函数时,该进程的⽤⼾空间代码和数据完全被新程序替换,从新程序的启动例程开始执⾏。调⽤exec并不创建新进程,所以调⽤exec前后该进程的id并未改变。
我们先用一个简单的示例来见见进程替换:
int execl(const char *path, const char *arg, ...);

利用最简单的exec函数,这里的path是可执行程序的地址,文件的地址可以用指针来表示,const char *arg,...这里表示可变参数,说明可以传入多个参数。

1.1可变参数

具体可见:

C 语言通过 <stdarg.h> 实现可变参数,图里重点用到这些:

  • va_list参数列表类型,本质是指针(比如 va_list args ,用来 “指向” 可变参数在栈里的位置)。
  • va_start(args, count)初始化,让 args 指向可变参数的 “起始位置”(count 是固定参数,用来定位可变参数从哪开始)。
  • va_arg(args, double)逐个取参数,按类型(这里是 double)从栈里读数据,读完后 args 自动指向下一个参数。
  • va_end(args)收尾清理,释放 va_list 相关资源(有些环境里是 “形式上” 的规范,实际也需调用)。

 栈内存视角:参数怎么存?

右侧 “栈帧”(main 调用 sum 的栈结构)是关键:

  • 固定参数count(图里是 3)是固定参数,先入栈,用来告诉函数 “可变参数有几个”。
  • 可变参数1.02.03.0 这些可变参数,按从右到左顺序入栈(C 语言调用约定常见规则),存在栈里等待读取。
 

代码里 sum(3, 1.0, 2.0, 3.0) 调用时,栈里布局大致是:

 
高地址 →  [count=3]  [1.0]  [2.0]  [3.0]  ← 低地址  
 

(实际栈增长方向是 “高地址 → 低地址”,但参数入栈顺序是 3 先压,然后 1.02.03.0 依次压,所以低地址侧是可变参数)

 代码流程:怎么读可变参数?

结合图里 sum 函数逻辑,流程是:

  1. 初始化va_start(args, count) → 让 args 指向可变参数起始位置(跳过固定参数 count,指向第一个可变参数 1.0 所在栈地址 )。
  2. 循环读取va_arg(args, double) → 每次按 double 类型从栈里取数据,累加到 total。取完后,args 自动偏移(因为 double 占 8 字节,所以 args 会 += sizeof(double) 指向下一个参数 )。
  3. 收尾va_end(args) → 释放资源,结束可变参数处理。

 类比 printf:可变参数的 “通用逻辑”

图里也提到 printf(const char *format, ...) ,它的逻辑和 sum 类似:

 
  • format 是固定参数(类似 count),用来 “描述可变参数的类型、个数”(比如 %d 对应 int%f 对应 double )。
  • 内部也是用 va_list 读取可变参数,按 format 里的占位符,逐个解析栈里的数据。

1.2 简单使用

知道可变参数之后我们开始简单使用一下execl,

通过以上例子我们提出两个疑问。

(1)为什么没打印“进程结束”?

(2)如果是在子进程中执行exec可以替换子进程的代码的数据吗?

好的,我们一一解决

(1)为什么没打印“进程结束”?

        替换了,你的进程,已经执行另一个程序的代码了你自己的代码,已经没有了!!

        程序替换函数,一旦调用成功,后续代码,不在执行,因为没有了!

如果失败呢??

        失败的话就会回到原代码,并且exe系列函数会有一个返回值,exe系列的函数,只要返回,必然失败! 程序替换,如果成功,不需要,也不会有返回值! 失败返回-1

(2)如果是在子进程中执行exec可以替换子进程的代码的数据吗?

子进程执行一个全新的程序,会影响父进程吗?不会!!进程必须具有独立性(父子代码共享,数据写时拷贝啊)

你可以理解成为,代码如果被替换,也要进行写时拷贝,会在内存中为子进程开辟数据的代码的空间。

由此可见,execl在这里就是起到一个加载器的作用。

2.exe家族的其他接口

这里我们在linux的命令行中man 一下exec。

可见,这里有六个接口,其实有七个,还有一个我们稍后再讲。

2.1命名理解

这些函数原型看起来很容易混,但只要掌握了规律就很好记。
l(list) : 表⽰参数采⽤列表
v(vector) : 参数⽤数组
p(path) : 有p⾃动搜索环境变量PATH
e(env) : 表⽰⾃⼰维护环境变量
函数名参数格式是否带路径是否使用当前环境变量
execl列表不是
execlp列表
execle列表不是不是,须自己组装环境变量
execv数组不是
execvp数组
execve数组不是不是,须自己组装环境变量

2.2exe家族的使用 

#include <stdio.h>
#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);
}

函数的使用比较简单,可以拿着格式自己试试,同时需要注意的是,这里的argv和envp是我们之前学到的命令行参数和环境变量,可以拿自己也可以直接在main函数中接收,可以直接拿着父进程的用,如果都要可以使用putenv()函数。

还有个点值得注意,在你的进程的地址空间,就如同全局变量一样,如果你不以参数形式传递给子进程,子进程也照样能拿到!!!!地址空间和页表!!!

3.六个接口与第七个的关系

上面我们不是提到了第七个接口,其实他叫做execve。

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

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

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

相关文章

场景题-3

如何实现一个消息队列 拆解分析主流的几种消息队列 1、基本架构 生产者Producer、消费者Consumer、Broker&#xff1a;生产者发送消息&#xff0c;消费者接受消息&#xff0c;Broker是服务端&#xff0c;处理消息的存储、备份、删除和消费关系的维护。 主题和分区&#xff…

vue2 项目中 npm run dev 运行98% after emitting CopyPlugin 卡死

今天在运行项目时&#xff0c;发现如下问题&#xff1a; 开始以为是node_modules依赖的问题&#xff0c;于是重新 npm install&#xff0c;重启项目后还是未解决。 在网上找了一圈发现有人说是 require引入图片地址没有写。在我的项目中排查没有这个问题&#xff0c;最后发现某…

73 LV的使用(XFS文件系统)

四 LV的使用 先创建一个LV01 lvcreate -L 10G lv01 datavg Logical volume "lv01" created. 将创建出来的LV01进行格式化 mkfs.xxx LV的名称(绝对路径) 绝对路径的组成:/dev/你创建VG的名字/LV的名字 mkfs.xfs /dev/datavg/lv01 挂载你的LV…

mybatis中判断等于字符串的条件怎么写

mybatis中判断等于字符串的条件怎么写_mybatis 等于字符串-CSDN博客 因为mybatis映射文件&#xff0c;是使用的ognl表达式&#xff0c;ognl是java语言&#xff08;强类型语言&#xff09;&#xff0c;会把‘X’解析成字符&#xff0c;而不是字符串。 所以比较字符串相等使用是…

C语言实现绝对值差值函数

在C语言中&#xff0c;可以编写一个函数来计算两个数的差值的绝对值。以下是一个简单的实现&#xff1a; #include <stdio.h> #include <stdlib.h> // 用于abs函数&#xff08;如果需要&#xff09; // 方法1&#xff1a;使用标准库函数 int absoluteDifference1…

Three.js中AR实现详解并详细介绍基于图像标记模式AR生成的详细步骤

文档地址 Three.js中AR实现详解 以下是Three.js中实现AR功能的详细解析&#xff0c;涵盖技术原理、实现步骤、核心组件及优化策略&#xff1a; &#x1f9e9; 一、技术基础 AR.js框架的核心作用 AR.js是Three.js实现AR的基石&#xff0c;提供以下核心能力&#xff1a; 多模…

Vue3.5 企业级管理系统实战(二十三):权限指令

在实际应用场景中&#xff0c;常常需要依据用户角色对按钮的操作权限实施控制。实现这一控制主要有两种方式&#xff1a;一种是借助前端指令基于角色进行权限管控&#xff0c;另一种是通过后台返回对应的权限属性来实现精细化控制。本文聚焦于前端权限指令展开探讨。 1 权限指…

软考 系统架构设计师系列知识点之杂项集萃(81)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;80&#xff09; 第145题 商业智能是企业对商业数据的搜集、管理和分析的系统过程&#xff0c;主要技术包括&#xff08;&#xff09;。 A. 数据仓库、联机分析和数据挖掘 B. 数据采集、数据清洗…

深入浅出Java ParallelStream:高效并行利器还是隐藏的陷阱?

在Java 8带来的众多革新中&#xff0c;Stream API彻底改变了我们对集合操作的方式。而其中最引人注目的特性之一便是parallelStream——它承诺只需简单调用一个方法&#xff0c;就能让数据处理任务自动并行化&#xff0c;充分利用多核CPU的优势。但在美好承诺的背后&#xff0c…

SQL Transactions(事务)、隔离机制

目录 Why Transactions? Example: Bad Interaction Transactions ACID Transactions COMMIT ROLLBACK How the Transaction Log Works How Data Is Stored Example: Interacting Processes Interleaving of Statements Example: Strange Interleaving Fixing the…

第R9周:阿尔茨海默病诊断(优化特征选择版)

文章目录 1. 导入数据2. 数据处理2.1 患病占比2.2 相关性分析2.3 年龄与患病探究 3. 特征选择4. 构建数据集4.1 数据集划分与标准化4.2 构建加载 5. 构建模型6. 模型训练6.1 构建训练函数6.2 构建测试函数6.3 设置超参数 7. 模型训练8. 模型评估8.1 结果图 8.2 混淆矩阵9. 总结…

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…

【大模型】大模型数据训练格式

1. SFT&#xff08;有监督微调&#xff09; 1.1 数据格式 JSONL&#xff08;每行一个 JSON 对象&#xff09;最为流行&#xff1b;也可用 CSV&#xff0f;TSV&#xff0c;但 JSONL 更灵活。字段设计 prompt&#xff1a;用户输入或任务指令&#xff08;通常以“系统指令&#…

[论文阅读] 人工智能 | 利用负信号蒸馏:用REDI框架提升LLM推理能力

【论文速读】利用负信号蒸馏&#xff1a;用REDI框架提升LLM推理能力 论文信息 arXiv:2505.24850 cs.LG cs.AI cs.CL Harnessing Negative Signals: Reinforcement Distillation from Teacher Data for LLM Reasoning Authors: Shuyao Xu, Cheng Peng, Jiangxuan Long, Weidi…

Cursor 1.0正式推出:全面解析你的AI 编程助手

目录 前言 一、BugBot&#xff1a;你的私人代码审查专家 二、Background Agent&#xff1a;7x24小时在线的云端开发伙伴 三、Jupyter Notebook 深度集成&#xff1a;数据科学家的福音 四、记忆功能 (Memories)&#xff1a;让 AI 更懂你的项目 五、MCP 与工具生态&#xf…

QILSTE 精巧电子元件H4-108FO/5M解析

型号&#xff1a;H4-108FO/5M 在电子元件的浩瀚宇宙中&#xff0c;H4-108FO/5M 仿佛一颗散发着独特光芒的恒星&#xff0c;其参数和特性交织成一张错综复杂的网络&#xff0c;既令人困惑又充满惊喜。这款型号的产品&#xff0c;以其 1.60.80.4mm 的微小尺寸&#xff0c;却蕴含…

第2章_Excel_知识点笔记

Excel 知识点总结&#xff08;第2章&#xff09; 来自&#xff1a;第2章_Excel_知识点笔记&#xff0c;原笔记 基础操作 状态栏&#xff1a;快速查看计数/求和等数据&#xff08;右键可配置&#xff09;。筛选&#xff08;CtrlShiftL&#xff09;&#xff1a;按条件显示数据…

【学习笔记】单例类模板

【学习笔记】单例类模板 一、单例类模板 以下为一个通用的单例模式框架&#xff0c;这种设计允许其他类通过继承Singleton模板类来轻松实现单例模式&#xff0c;而无需为每个类重复编写单例实现代码。 // 命名空间&#xff08;Namespace&#xff09; 和 模板&#xff08;Tem…

yolo 训练 中间可视化

yolo训练前几个batch&#xff0c;会可视化target: if plots and ni < 33:f save_dir / ftrain_batch{ni}.jpg # filenameplot_images(imgs, targets, paths, f, kpt_labelkpt_label)

【Linux】虚拟机代理,自动化脚本修改~/.bashrc

二选一执行 {echo ""echo "# Cla Verge代理设置 "echo "alias use-proxyexport http_proxy\"socks5h://192.168.88.1:7897\"; export https_proxy\"socks5h://192.168.88.1:7897\""echo "alias use-proxy-httpexport…