• Linux下的进程控制-进程程序替换


    这篇主要说一下Linux下的进程控制中最后一部分内容:进程程序替换
    在这里插入图片描述

    1. 进程程序替换

    1.1 为什么要进程程序替换

    我们知道:子进程一般执行的是父进程的代码片段。但是如果我们想让创建出来的子进程去执行其它的程序呢?我们就需要进程程序替换!!!

    我们一般在服务器设计(Linux编程)的时候,往往需要子进程干两件种类的事:
    1.让子进程执行父进程的代码片段(服务器代码)
    2.让子进程执行磁盘中一个全新的程序(shell,想让客户端执行对应的程序,通过我们的进程执行其他人写的进程代码等等)。

    1.2 替换原理

    在这里插入图片描述
    这是我们父进程在运行时,把磁盘中可执行程序中的代码和数据加载到内存中。当我们父进程fork后。子进程的PCB和虚拟内存以父进程为模板,代码共享父进程的,数据也以写时拷贝的方式共享。
    在这里插入图片描述
    此时,在磁盘中有个新的程序,让子进程数据和代码不在和父进程共享。让子进程去执行这个新文件。这样子进程的页表会进行更新指向新的代码段和数据段。
    在这里插入图片描述
    替换原理:
    1.将磁盘中的程序,加载入内存结构。
    2.重新建立页表映射,谁执行程序替换,就重新建立谁的映射。
    效果:让父子进程彻底分离,并让子进程执行一个全新的程序。在这里也并没有产生新的进程。

    1.3 如何进行程序替换

    因为我们是从磁盘加载到内存,一个硬件把数据转移到另外一个硬件中,这个工作是由操作系统完成的,所以我们需要一个系统函数来完成。在Linux云服务器上由7个程序替换函数。

    1.3.1 execl函数

    我们先来看一个最简单的:
    在这里插入图片描述
    这三个点叫做可变参数:它的作用是按照用户的意愿传入大小或者数量不等的各个参数。

    那么,如果我们想执行一个全新的程序,我们需要做几件事情呢
    1. 先找到这个程序在哪里?
    2. 程序是怎么执行的?是带选项执行,还是不带选项执行?

    那么,这个execl函数第一个参数的意思是:就是传入程序的路径,第二个传入的就是你程序是如何来执行的(命令行怎么写,这个参数就怎么填),最后必须是NULL,标识如何执行程序的参数传递完毕

    现在我们写一个最简单的例子:
    在这里插入图片描述
    在这里插入图片描述
    在OS中,命令也是一个程序,我们来运行一下:
    在这里插入图片描述
    我们可以从结果看到:它这里执行了ls -a -l这个命令。我们再来看一个:
    在这里插入图片描述
    这个不带选项的。我们运行一下:
    在这里插入图片描述
    它也执行了pwd这个命令。但是大家有没有发现一个问题:它第二个打印没有进行。
    原因是:一旦替换成功,是将当前的代码和数据全部替换了所以,后面的printf已经被替换了,该代码已经不存在了。

    在这里插入图片描述
    那么我们看这个函数的返回值有什么用呢?要不要判断返回值呢
    答案是:不需要。因为当替换成功了,就不会有返回值了,它就执行其它的代码了,你的返回值没有任何作用。而失败的时候,必然会继续向后执行,最多通过得到什么原因导致的替换失败!!!

    我们可以用一个失败的来运行一下:
    在这里插入图片描述
    这里我们是没有这个命令的。
    在这里插入图片描述

    1.3.2 引入子进程的程序替换

    看下面的代码:
    在这里插入图片描述
    运行一下:
    在这里插入图片描述
    子进程进行程序替换,会不会影响父进程?
    答案是:不会的。因为进程的独立性。
    那么它是如何做到的呢?
    原因是:当程序替换时,我们可以理解为:代码和数据都发生了写时拷贝完成父子的分离

    1.3.3 execv函数

    在这里插入图片描述
    这个函数也是程序替换函数。第一个参数是:程序的路径。第二个参数:如何执行。
    它和execv的区别就是它是一个指针数组。execl是一个一个传参数,而这个是把参数放到数组里,然后传这个数组。

    举个例子:
    在这里插入图片描述
    运行结果如下:
    在这里插入图片描述

    1.3.4 execlp函数和execvp函数

    在这里插入图片描述
    这里的第一个参数有什么含义呢?它和execl有什么区别呢?
    它第一个参数传的是你要执行什么程序,但是execl需要我们写路径,而这个execlp不需要我们写路径,直接写程序名就行了。因为它是默认在PATH下去寻找的

    举个例子:
    在这里插入图片描述
    我们来看一下运行结果:
    在这里插入图片描述
    那么execvp也是一样的道理,这里就不多说了。
    在这里插入图片描述

    1.3.5 如何执行其它语言的程序

    目前我们执行的都是系统命令,如果要执行自己写的C/C++程序,或者执行其它语言写的程序呢
    我们写一个C++的程序:
    在这里插入图片描述
    我们要形成两个可执行程序,让其中一个可执行程序去执行另外一个可执行程序:
    在这里插入图片描述
    但是我们来运行一下:
    在这里插入图片描述
    但是我们只能执行第一个,因为makefile默认执行一个可执行程序。我们需要这样写:
    在这里插入图片描述
    这样我们就可以一下形成两个可执行程序:
    在这里插入图片描述
    然后看一下我们写的程序:
    在这里插入图片描述
    这里用相对路径也可以,只要能找到它就行了:
    在这里插入图片描述
    然后,我们看一下运行结果:
    在这里插入图片描述
    成功的用myexec执行了mycmd。

    1.3.6 execle函数

    在这里插入图片描述
    这里的第三个参数是:环境变量的意思。

    举个例子:
    在这里插入图片描述
    这里我们写了一个系统里的环境变量PATH,和一个我们自己写的环境变量MYPATH(系统里没有)。
    在这里插入图片描述
    这样就是我们自己写了一个环境变量,然后调用这个函数时导入。然后我们看一下运行结果:
    在这里插入图片描述
    我们看到什么都没有打印,我们把PATH先注释掉:
    在这里插入图片描述
    然后看运行结果:
    在这里插入图片描述
    我们看到它把MYPATH打印出来了。原因是:添加环境变量给目标进程,是覆盖式的。
    那么我们该如何解决这个问题呢?
    在这里插入图片描述
    我们这里使用环境变量的指针来传入。
    在这里插入图片描述
    因为系统里没有MYPATH环境变量,所以我们要export设置一下。
    在这里插入图片描述
    这样就都能打印出来了。

    1.3.7 execve函数和execvpe函数

    在这里插入图片描述
    那么execvpe我就不多说了,就是把上面的结合起来就行了。
    在这里插入图片描述
    那么现在就出现一个问题:为什么execve是单独的
    原因是:execve是系统接口,而其余6个是对系统接口的封装。这样做的原因就是适配各种应用场景

    这些函数原型看起来很容易混,但只要掌握了规律就很好记:
    在这里插入图片描述

  • 相关阅读:
    新一代自动化测试神器Playwright
    【设计模式】Java设计模式 - 备忘录模式
    文件包含笔记
    【Linux】Base64编码
    2023年高教社杯全国大学生数学建模竞赛赛题
    DNS域名解析过程
    【我的OpenGL学习进阶之旅】关于欧拉角、旋转顺序、旋转矩阵、四元数等知识的整理
    MSDC 4.3 接口规范(25)
    05 网络和防火墙等其他
    SpringCloud-Config&Bus
  • 原文地址:https://blog.csdn.net/qq_52154068/article/details/127956949