进程的程序替换(exec函数)【Linux】

进程的程序替换详解exec函数【Linux】

  • 程序替换的原理
  • exec系列函数
    • 函数理解
    • 命令理解(助记)
  • 关于程序替换中环境变量的解释
  • exec函数之间的关系
  • exec函数的使用
    • execl
    • execlp
    • execle
    • execv

程序替换的原理

  进程的程序替换就是让子进程执行新程序, 执行全新的代码和数据,不再和父进程有瓜葛。
替换原理

  用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
在这里插入图片描述

  • 也就是说程序替换的作用是为了完成一些特定的任务,需要去执行其他的程序。
  • 使用exec系列函数可以达到程序替换的目的。
  • 程序替换会重新创建虚拟地址,页表,然后将磁盘中的文件加载进物理内存。
  • 程序替换会自动释放原来的进程虚拟内存和页表。
  • 程序替换时, 虚拟地址空间和页表的映射会变化,PCB里的优先级等信息不变。

exec系列函数

  以下函数的参数末尾都一定需要带上一个==“NULL”==。

#include <unistd.h>

// path是要替换的程序文件路径+文件名,main函数的argv参数中是什么,这里就怎么写。
int execl(const char *path, const char *arg, ...);

// 会自动到环境变量PATH中根据file寻找新程序的文件,所以file可以直接写成文件名即可。
int execlp(const char *file, const char *arg, ...);

// 自己可以维护环境变量
int execle(const char *path, const char *arg, ...,char *const envp[]);

// 将命令装入数组中,下面的三个函数其余的跟上面的三个函数都是一样的。
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

函数理解

  • 这些函数执行成功的话,则加载进新的程序,启动新程序并且从新程序的的开头开始执行,不再返回。
  • 如果执行成功,原程序中的后续代码将不再执行,因为eip(程序计数器),已经改变到新程序处。
  • 如果调用出错则返回-1.
  • 所以exec只有出错的返回值没有成功的返回。毕竟成功的返回值是无意义的。
  • 除了系统文件,也可以替换成自定义文件,如: .sh,python,java都可以调用。

命令理解(助记)

  • l(list) : 表示参数采用列表

  • v(vector) : 参数用数组

  • p(path) : 有p自动搜索环境变量PATH

  • e(env) : 表示自己维护环境变量

    在这里插入图片描述

关于程序替换中环境变量的解释

  1. 当进行程序替换时,子进程对应的原始环境变量是从父进程中来的,bash拥有最原始的环境变量,后代进程可在其基础上添加并继承自己的父进程的环境变量。
  2. 环境变量被继承是一种默认行为,不受程序替换的影响。(程序替换只替换代码和数据,不替换环境变量)因为创建子进程都以父进程为模板,父子进程的环境变量指向同一块物理地址,所以一样。
  3. 如何让子进程获得环境变量。
  • 将父进程的环境变量原封不动的传递给子进程(1. 直接用。 2. 直接传)。
  • 想传递自己的环境变量,可以直接构建环境变量表,给子进程传递(是覆盖原来环境变量式的传递)
  • 新增传递(可以利用putenv()函数)。

exec函数之间的关系

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

下图exec函数族 一个完整的例子:

在这里插入图片描述

exec函数的使用

execl

int execl(const char *path, const char *arg, ...);

// test.cpp:
#include <iostream>
#include <unistd.h>
int main()
{
    pid_t fd = fork();
    if (fd == 0)
    {
        // child
        execl("/root/Y23_12_28/t", "t", "-start", NULL);
    }
    return 0;
}
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("%s %s\n", argv[0], argv[1]);
    printf("我是t.cpp进程\n");

    return 0;
}

在这里插入图片描述

execlp

int execlp(const char *file, const char *arg, ...);
此时我们打印环境变量PATH:

#include <stdio.h>
#include <unistd.h>
#include <cstdlib>
int main(int argc, char *argv[])
{
    printf("%s", getenv("PATH"));

    return 0;
}

在这里插入图片描述
打印当前的文件路径cwd:
在这里插入图片描述
  对比会发现PATH中没有cwd,若是直接使用execlp的话一定会报错。我们来试一下:

#include <stdio.h>
#include <unistd.h>
int main()
{
    pid_t fd = fork();
    if (fd == 0)
    {
        // child
        int ret = execlp("t", "t", "-start", NULL);
        if (ret < 0)
        {
            printf("execpl错误\n");
        }
    }
    return 0;
}

在这里插入图片描述
  果然报错了,原因是PATH中没有cwd,无法自动找到文件位置。所以我们需要添加环境变量,使用putenv()函数,使用这个函数需要注意的是,会将原来的PATH内容全部清除,然后再添加新的PATH。

//test.cpp:
#include <stdio.h>
#include <unistd.h>
#include <cstdlib>
int main()
{
    pid_t fd = fork();
    if (fd == 0)
    {
        char *old_PATH = getenv("PATH");
        char new_PATH[] = ":/root/Y23_12_28";
        char new1[1000];
        sprintf(new1, "PATH=%s%s", old_PATH, new_PATH);
        putenv(new1);
        // child
        int ret = execlp("t", "t", "-start", NULL);
        if (ret < 0)
        {
            printf("execpl错误\n");
        }
    }
    return 0;
}
//t.cpp:
#include <stdio.h>
#include <cstdlib>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{

    printf("%s %s\n", argv[0], argv[1]);
    printf("我是t.cpp进程\n");
    return 0;
}

  这里有一个需要注意的地方,就是合并新老PATH时,一定不要忘记PATH=%s%sPATH=
在这里插入图片描述

execle

int execle(const char *path, const char *arg, ...,char *const envp[]);
  多出来的这个e表明了可以自己设定环境变量:

// test.cpp
#include <stdio.h>
#include <unistd.h>
#include <cstdlib>
int main()
{
    pid_t fd = fork();
    if (fd == 0)
    {
        char *const envp[] = {"PATH=/root/Y23_12_28", "NULL"};
        // child
        int ret = execle("t", "t", "-start", NULL);
        if (ret < 0)
        {
            printf("execpl错误\n");
        }
    }
    return 0;
}

在这里插入图片描述

execv

int execv(const char *path, char *const argv[]);
  v表示使用数组来装载命令, 而不是vector;

#include <stdio.h>
#include <unistd.h>
#include <cstdlib>

int main()
{
    pid_t fd = fork();
    if (fd == 0)
    {
        // child
        char *arg[3] = {"t", "-start", "NULL"};
        int ret = execv("/root/Y23_12_28/t", arg);
        if (ret < 0)
        {
            printf("execpl错误\n");
        }
    }
    return 0;
}

在这里插入图片描述
  至于execvp和execve在这里就不过多赘述了。


    😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用华为云鲲鹏弹性云服务器部署Discuz

本实验将在华为云鲲鹏弹性云服务器CentOS系统的实例上&#xff0c;部署Discuz!项目&#xff0c;并进行初步的安装测试。 注意&#xff1a;官网文档有些链接失效&#xff0c;本文在官方文档的基础上作出修改&#xff0c;具体参见Discuz安装这一步 操作前提&#xff1a;登录华为…

Android : 使用GestureDetector 进行手势识别—简单应用

示例图&#xff1a; GestureDetector 介绍&#xff1a; GestureDetector 是 Android 开发中用于识别和处理手势的一个类。它允许开发者检测用户在触摸屏上的各种手势&#xff0c;如滑动、长按、双击等。通过使用 GestureDetector&#xff0c;您可以轻松地为应用程序添加手势识…

FPGA设计时序约束十五、Set_Bus_Skew

目录 一、序言 二、Set Bus Skew 2.1 基本概念 2.2 设置界面 2.3 命令语法 2.4 报告分析 三、工程示例 3.1 工程代码 3.2 时序报告 四、参考资料 一、序言 在时序约束中&#xff0c;对时钟的约束除了set clock latency,set clock uncertainty,set input jitter外&…

蜥蜴目标检测数据集VOC格式1400张

蜥蜴&#xff0c;一种爬行动物&#xff0c;以其独特的形态和习性&#xff0c;成为了人们关注的焦点。 蜥蜴的外观多样&#xff0c;体型大小不一。它们通常拥有长条的身体、四肢和尾巴&#xff0c;鳞片覆盖全身&#xff0c;这使得它们能够在各种环境中轻松移动。大多数蜥蜴拥有…

在Ubuntu22.04上部署Stable Diffusion

在AI绘画软件领域Stable-Diffusion&#xff08;简称SD&#xff09;在开源领域绝对是不二之选&#xff0c;他的插件方式可以让此软件具有更多的功能&#xff0c;开发者社群为此提供了大量免费高质量的外接预训练模型&#xff08;fine-tune&#xff09;和插件&#xff0c;并持续维…

力扣-42.接雨水

题目&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组[0,1,0,2…

day06、SQL语言之概述

SQl 语言之概述 6.1 SQL语言概述6.2 SQL语言之DDL定义数据库6.3 SQL语言之DML操纵数据库 6.1 SQL语言概述 6.2 SQL语言之DDL定义数据库 6.3 SQL语言之DML操纵数据库

mysql死锁排查

查看正在进行中的事务 SELECT * FROM information_schema.INNODB_TRX;字段解释trx_id唯一事务id号&#xff0c;只读事务和非锁事务是不会创建id的trx_state事务的执行状态&#xff0c;值一般分为&#xff1a;RUNNING, LOCK WAIT, ROLLING BACK, and COMMITTING.trx_started事务…

智能手机2024:狂卷“微创新”后如何突破新机遇

文 | 智能相对论 作者 | 楷楷 2023年&#xff0c;智能手机市场终于开始展露曙光。Counterpoint Research数据显示&#xff0c;2023年10月全球智能手机销量同比增长5%&#xff0c;智能手机市场出货量在经历了连续27个月的同比下滑后&#xff0c;首次出现同比正增长。 特别是在…

Redis学习笔记(1)——感谢尚硅谷官方文档

Redis学习笔记&#xff08;1&#xff09;——感谢尚硅谷官方文档 1. NoSQL1.1 NoSQL数据库概述1.2 各种NoSQL数据库 2. Redis数据库安装2.1 安装条件2.2 Widows下如何安装Redis?2.3 Linux下如何安装Redis? 3. Redis介绍3.1 Redis 简介3.2 Redis 优势3.3 Redis与其他key-value…

深入理解CRON表达式:时间调度的艺术

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

three.js相机按照指定路线在建筑模型中漫游(支持开始,暂停)

three.js相机按照指定路线在模型中漫游&#xff08;支持开始&#xff0c;暂停&#xff09; 关键点 相机运动曲线 // 相机路线 const points [new THREE.Vector3(0, 40, 300),new THREE.Vector3(50, 40, 300),new THREE.Vector3(50, 40, 50),new THREE.Vector3(150, 40, 50),…

集群渲染是?渲染农场是?两者与云渲染关联是什么

在数字化浪潮不断推进的当下&#xff0c;渲染技术在多个行业中发挥着至关重要的作用&#xff0c;尤其体现在电影制作、建筑可视化以及电子游戏开发等领域。在众多渲染技术中&#xff0c;集群渲染、渲染农场以及云渲染特别受到业界的重视。本文旨在阐述这些概念的含义以及它们之…

Web 自动化测试过程中会遇到哪些问题?

作者&#xff1a;木可 链接&#xff1a;https://www.zhihu.com/question/636965892/answer/3341410674 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 Web自动化是指使用测试脚本来自动执行网页上的任务。这包括填…

vue3安装vue-tools

https://github.com/vuejs/devtools/tree/v6.5.0/packages 打开浏览器扩展程序 这个文件直接拖进扩展程序

深度神经网络中的混合精度训练

Mixed-Precision Training of Deep Neural Networks | NVIDIA Technical Blog 目录 混合精度成功训练的技术 FP32 累加 损失缩放 loss scaling FP32 Master Copy of Weights 混合精度训练迭代过程 AMP混合精度训练介绍 FP16和FP32的区别 FP16的优势 FP16的问题 解决P…

select for update会锁表还是行锁还是其它

select for update含义 select查询语句是不会加锁的&#xff0c;但是 select for update除了有查询的作用外&#xff0c;还会加锁呢&#xff0c;而且它是悲观锁哦。至于加了是行锁还是表锁&#xff0c;这就要看是不是用了索引/主键啦。 没用索引/主键的话就是表锁&#xff0c…

2下载Spring,第一个Spring程序+引用Log4j2

https://www.yuque.com/dujubin/ltckqu/kipzgd#&#xff0c;注意的是&#xff0c;现在&#xff08;202401&#xff09;SpringFramework从release搬到了snapshot下&#xff0c;在这下面找到6.0.2下载. 下载后解压到文件夹&#xff0c;整个框架包含非常多jar包。 然后就可以在p…

C#中使用as关键字将对象转换为指定类型

目录 一、定义 二、示例 三、生成 使用as关键字可以将对象转换为指定类型&#xff0c;与is关键字不同&#xff0c;is关键字用于检查对象是否与给定类型兼容&#xff0c;如果兼容则返回true&#xff0c;如果不兼容则返回false。而as关键字会直接进行类型转换&#xff0c;如果…

金融中IC和IR的定义

当谈到金融领域时&#xff0c;IC&#xff08;Information Coefficient&#xff09;和IR&#xff08;Information Ratio&#xff09;通常是用来评估投资组合管理绩效的指标。它们都涉及到投资者对信息的利用和管理的效果。 信息系数&#xff08;IC - Information Coefficient&a…