Linux:进程程序替换(exec函数簇)


PCB有什么用:PCB描述了程序的运行过程
为什么创建子进程:为了完成一个任务
进程替换就是想让创建出来的子进程执行全新的程序

程序就是磁盘上的文件

  • 程序在哪,先要找到程序的路径
  • 如何执行,程序可能携带选项去执行

进程程序替换:

替换正在运行的程序,让正在运行的进程执行新程序;

进程程序替换原理及过程:

  • 程序运行起来时是一个PCB,里面有一个变量是内存指针
  • 内存指针指向了进程虚拟地址空间
  • 通过页表结构和物理内存映射,程序在运行起来后,代码段里就运行着所写代码;

  • 如果让该程序替换成另一个程序,就需要代码中调用进程替换函数;
  • 当前运行的程序会更新代码段和数据段,并且更新堆栈;
  • 所以当前的进程就运行其它程序,或者说是新程序

注意:

  • 进程程序替换完后,进程就在指向新程序,但进程号不变,意味着当前进程不是新的进程;
  • 但当前进程在执行新的程序

在代码中如何进行替换,就需要了解exec函数簇

exec函数簇

在这里插入图片描述

execl:

在这里插入图片描述

例:ls -al替换ls

  • 第一个user bin是可执行程序本身,
    第二个user bin是路径,
    -al是命令行参数,
    …是可变参数列表
  • 注:第一个参数必须是可执行程序本身;
    NULL:命令行参数结束的标志
    在这里插入图片描述
    运行情况:
  • 屏幕先输出“准备替换”,然后还输出了当前路径下的文件信息,没有输出“替换失败”

原因:

  • 程序替换成功后,就会运行新进程的代码,不会运行原进程代码
  • 新进程的代码是展示当前路径下所有文件的信息;
  • “替换失败”这个printf语句是原进程中的,

execl函数能打印出返回值,就表示替换失败

execlp:

p代表path,只在path中找

在这里插入图片描述在这里插入图片描述
另一个例子:execlp(“pwd”, “pwd”, NULL);

第一个ls供系统去找执行谁
第二个ls是想怎样执行的

execle:

给程序传入对应的环境变量信息
执行自己的程序,或者其它语言写的程序
第一个参数指定路径,可以用绝对路径,也可以是相对路径

在这里插入图片描述
在这里插入图片描述

myexec是原程序,mycmd是待进行替换的程序
第三个参数是一个字符指针数组
myexec程序使用execle函数,将上述自定义的环境变量作为execle函数的第三个参数后,myexec连path都打印不出来了

如果不想覆盖,那么需要把新环境变量传给待替换的进程

  1. 先在bash处导入环境变量
  2. 将原程序中的execle函数的第三个参数设置为environ

有个环境变量是PATH

在这里插入图片描述在这里插入图片描述


有环境变量:
在这里插入图片描述

想传入自定义的环境变量给待替换的程序

规律:

  1. 函数名带l:当前函数是一个可变参数列表的函数
  2. 函数名带p:当前函数会自动搜索环境变量
  3. 函数名带e:程序员需要自己组织环境变量
  4. 函数名带v:传递给待要替换的可执行程序行参数的组织格式为指针数组,注意的点与可变参数两点相同
  5. 以上函数都带有l,函数名中没有l表示当前函数的参数,不是可变参数列表的形式

在这里插入图片描述

execve:系统调用函数

在这里插入图片描述在这里插入图片描述

execvp:

在替换的程序都是系统指令程序时,每次都要设置程序的路径
针对这种运行的都是系统指令程序的场景,大佬们就针对execve封装了一个新函数,第一个参数不用指定路径,默认会在PATH环境变量指定的路径下找

这个函数中也有个特殊的,环境变量默认使用当前进程已经有的环境变量,不用手动设置环境变量

在这里插入图片描述在这里插入图片描述

execv:

每次替换程序的时候,环境变量多数情况没有什么好设置的,直接使用已经有的就行

在这里插入图片描述在这里插入图片描述

execl和execv只有传参方式的区别
l:list
v:vector

在这里插入图片描述
execve是系统调用函数,其余5个函数都是库函数

进程替换场景

1.bash的应用场景:

之所以我们能在命令行执行各种命令(例如ls),本质上是我们和bash命令行解释器进行交互;
过程:

  1. 当我们在命令行输入了一个可执行程序后,这个程序就成为了bash代码块中的一部分,然后bash再去创建一个子进程,
  2. 该子进程是拷贝了父进程的PCB,子进程中的代码也是bash中的代码,最终的结果是运行我们写的可执行程序

这里面就用到了让子进程进行程序替换的技术

在这里插入图片描述

2.守护进程:一个产品是要一直为用户提供服务的,这个产品代码不能百分百不崩溃;
这里面就用到了守护进程:保护业务进程

怎样保护

  • 启动业务进程时,不是启动业务程序,而是启动守护进程;
  • 守护进程创建一个子进程,让子进程进行进程程序替换,成为业务程序进程;
  • 替换完后守护进程创建出来的子进程就相当于业务进程,正常为用户服务;

  • 守护进程和业务进程(子进程)进行进程通信(守护进程会循环判断业务进程的状态),让守护进程得知业务进程的情况:
  • 业务进程正常:则守护进程不做处理;
  • 业务进程崩溃或异常:则守护进程重新启动一个子进程,让子进程进行进程程序替换,和上述步骤一样

业务进程(子进程)会给内存返回一个时间,守护进程会读取并保存,下一次守护进程拿到的时间不变,则说明业务进程程序崩溃或异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
exec函数Linux系统中的一个系统调用,用于在当前进程执行一个新的程序替换当前进程代码和数据,从而使新程序成为当前进程exec函数有多个变种,包括execl、execle、execlp、execv、execvp等。它们的区别在于参数的传递方式和可执行文件的搜索路径等不同。 一般情况下,exec函数会覆盖当前进程的地址空间,因此,调用exec函数后,原进程代码和数据都会被新进程替换,从而新进程获得了原进程的权限和资源。因此,exec函数常用于创建子进程并在子进程执行一个新的程序。 示例代码: ```c #include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { printf("This is the original process.\n"); // 创建子进程 pid_t pid = fork(); if (pid == -1) { perror("fork failed"); return -1; } else if (pid == 0) { // 在子进程执行ls命令 execl("/bin/ls", "ls", "-l", NULL); perror("execl failed"); return -1; } else { // 父进程等待子进程结束 wait(NULL); printf("Child process finished.\n"); } return 0; } ``` 在上面的代码中,我们创建了一个子进程,并在子进程执行了ls命令。在执行execl函数时,第一个参数是可执行文件的路径,第二个参数是可执行文件的名称,后面的参数是传递给可执行文件的参数列表。如果execl函数执行成功,则不会返回,否则会返回-1,并输出错误信息。在父进程中,我们使用wait函数等待子进程结束,并输出相应的信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值