详解:进程程序替换

一、前言

一般情况下,对应的语言写的程序只能调用对应的语言的接口,而不能调用其他语言的接口,如C++不能调用Java或者Python或者Shell等语言的接口,那么如果我们想要调用别人写的程序应该怎么办呢?那么进程程序替换就能够很好地帮助我们解决这个问题,这在很大程度上减少了我们编程的成本,学会进程程序替换,在很多时候,如果有现成的程序,那么我们不需要自己再去写一个,是不是方便很多了?

二、什么是进程程序替换?

所谓进程程序替换,顾名思义,就是使用一个新的程序替换原有的程序,进程将执行新程序的代码,而不再执行原有程序的代码,前面我们已经学习了如何创建一个进程,一般情况下,进程程序替换都不会使用父进程直接进行进程程序替换,而是让父进程调用fork()函数创建一个子进程,让子进程去执行一个新的程序即可

三、进程程序替换的原理

  • 进程替换前的效果图
    当一个进程成功创建一个子进程之后,父子进程的情况如下图所示:
    在这里插入图片描述
    这个时候,我们这里先针对代码和数据进行分析,其他内容暂不做考虑,此时父子进程都没有修改代码和数据,因此,父子进程的代码和数据都是指向同一块内容的,也就是代码和数据共享的,如果其中一方对数据进行修改,则这一方就会进行写时拷贝,如果想要执行不同的代码,则此时就要进行进程程序替换
  • 进程程序替换的原理
    假如刚开始父子进程都是执行程序a.exe,后面,想要让子进程执行b.exe了,那么此时就要进行进程程序替换,替换的过程就是首先将b.exe从磁盘加载进内存,然后重新建立子进程的页表更新子进程的页表中的映射关系,注意,这里修改的是页表中的物理地址而不是虚拟地址,此时父子进程代码块中虚拟地址是一样的,但是通过页表映射出来的物理地址是不一样的,从而实现父子进程的代码彻底分离,此时父子进程的代码是互不干扰的,很好地满足了进程的独立性
  • 进程替换之后的效果图
    在这里插入图片描述

四、为什么要进行进程程序替换?

在学习进程程序替换之前,我们知道当一个父进程创建一个子进程之后,父子进程的代码是共享的,子进程只能执行父进程的代码块,但是现在我们的需求增加了,我们不仅要让子进程能够执行父进程的代码块,也要能够让子进程能够做一些父进程不能做的事情,也就是能够执行一个全新的代码(程序),这样就能实现父子进程做的事情有所差异,大大提高了办事效率,同时也使父子进程的代码彻底分离,维护进程的独立性

五、如何进行进程程序替换?(常见进程程序替换系统调用接口)

在学习使用进程程序替换的相关接口之前我们首先需要明确一点,这个在使用接口的时候需要做什么事情,很明显,最基本的我们首先得知道这个程序在哪里,其次,我们还需要知道怎么执行这个程序,在我们前面学习一些指令的时候,有些指令是可以携带选项的有些指令可以不用携带选项。总结起来就是我们需要知道要执行的程序的路径和怎么执行新程序

  1. execl
  • 查看execl的使用方法
    在这里插入图片描述
  • execl的使用
  • 源代码
    在这里插入图片描述
  • makefile文件
    在这里插入图片描述
  • 实验结果
    在这里插入图片描述
    上面的实验是没有子进程的,是一个纯单进程的实验,下面将演示一个多进程的例子执行ls指令,而且我们会发现一个现象,我们明明在源代码中写了两条printf函数语句,但是结果只有一条打印出来,原因是,当我们进行程序替换之后,子进程将不再执行原来的父进程的代码块,由进程程序替换的结果我们可以知道,子进程中的代码内容完全被替换成新程序的代码
  • execl多进程实验
    源代码
    在这里插入图片描述
    makefile文件
    在这里插入图片描述
    实验结果
    在这里插入图片描述
    实验分析
    上面的实验思路就是父进程创建一个子进程,然后本来子进程是要执行父进程的代码块和父进程进行代码共享的,但是我们在子进程中调用execl函数接口,因此,在子进程中会进行程序替换
  1. execv函数接口的使用
  • 查看手册
    在这里插入图片描述
    这个函数和上面介绍的execl是类似的,都需要做两件事,第一知道新程序的路径,第二知道怎么执行新程序(是否携带选项进行执行),但是这个函数和上面介绍的函数的区别就是这个函数的第二个参数是一个字符指针数组,上面哪个函数是一个一级字符指针,其实区别就在于,上面那个函数传参传的是字符串列表,这个函数传参传的是字符指针数组
    实验演示:
  • 源代码
    在这里插入图片描述
  • makefile文件
    在这里插入图片描述
  • 实验结果
    在这里插入图片描述
    需要注意的是
  • execv函数中使用的是字符指针数组,而不是传字符串列表
  • 数组中的字符串是常量字符串,也就是const char类型的,而这个字符指针数组中存放的又是char的,是支持修改的,因此这里需要将const char强转为char类型
    在这里插入图片描述
  1. execlp函数接口的使用
  • 查看手册
    在这里插入图片描述
  • execlp的使用(实验演示)
    源代码
    在这里插入图片描述
    makefile文件
    在这里插入图片描述
    实验结果
    在这里插入图片描述
    execlp中的p指的是环境变量中的PATH,指的是系统直接到环境变量PATH中去寻找对应程序,因此在传第一个参数的时候不需要带路径
    注意:
    在这里插入图片描述
    这个参数列表中有两个"ls",我们需要知道的是这两个ls的含义是不一样的,是不能省略的,第一个是告诉系统要执行哪个程序,好让系统知道去找谁,第二个是在函数的第二个参数之中的,也就是为了告诉系统怎么执行这个程序
  1. execvp的使用
  • 查看手册
    在这里插入图片描述
  • 实验演示使用方法
    源代码
    在这里插入图片描述
    makefile文件
    在这里插入图片描述
    实验结果
    在这里插入图片描述
  1. execle函数接口的使用
  • 查看手册
    在这里插入图片描述
  1. execle的使用
  2. 这个接口的作用就是可以给想要执行的程序传入自己定义的环境变量,这个接一共有三个参数,前面两个参数和前面的接口一样,第三个参数可以覆盖式的将想要传的环境变量传给想要执行的程序,一般两种情况,第一种就是直接传入自定义的环境变量,第二种就是通过environ,并将自定义的环境导出为系统的环境变量,那么这样就可以了
    源代码
    在这里插入图片描述
    makefile文件(形成多可执行程序)
    在这里插入图片描述
    导出自己的环境变量
    在这里插入图片描述

实验结果
在这里插入图片描述
注意:
在这里插入图片描述

上面的实验中,我们使用函数execle传入第三方变量environ,environ的作用是获取系统中的环境变量,上面这个代码的意思就是将这个变量environ传给test程序,那么如果想要在该程序中打印出自定义的环境变量,则需要将自定义环境变量加入系统环境变量,test程序才能获取,如果没有加入系统环境变量,则getenv()函数获取不到对应的环境变量则会返回空指针,那么就会导致printf函数打印空指针从而造成程序崩溃
除了上面的情况外,我们也可以自己传入自定义的环境变量
源代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里需要注意:需要将PATH所在行的代码进行注释,因为execle传入环境变量的方式是覆盖式的,所以当向该程序传入自定义环境变量之后,原来的环境变量就不存在了,那么不存在的话,通过getenv()去获取的话结果就会出现空指针,那么再对空指针进行打印就会出现段错误

makefile文件
在这里插入图片描述
实验结果
在这里插入图片描述
其中上面第一种通过environ来获取环境变量的方式其实我们也可以不采用程序替换的方式进行获取,按照普通的一个程序也可以获取到自定义变量,因为只需要通过export将该自定义环境变量导出为系统的环境变量即可,其实本质上是一样的,下面给出演示
源代码:
在这里插入图片描述
在这里插入图片描述
实验结果:
在这里插入图片描述

总结

今天我们主要介绍了进程程序替换及其基本原理,还有介绍了很多程序替换有关的函数接口

  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值