返回顶部
首页 > 资讯 > 操作系统 >【Linux】进程的程序替换
  • 393
分享到

【Linux】进程的程序替换

linux运维服务器 2023-08-22 18:08:40 393人浏览 安东尼
摘要

文章目录 1. 程序替换1.创建子进程的目的是什么?2.了解程序是如何进行替换的3. 程序替换的基本原理当创建进程的时候,先有进程数据结构,还是先加载代码和数据?程序替换是整体替换,不是局部替换execl 返回值 4. 替换函

1. 程序替换

1.创建子进程的目的是什么?

目标:为了让子进程帮父进程执行特定的任务

  • 具体做法:1. 让子进程执行父进程的一部分代码

红框中的代码实际上是父进程的代码,在没有执行fork之前代码就有了,在没有创建子进程之前,父进程的代码加载到内存了,子进程被创建出来是没有独立的代码,这个代码是父进程的代码,父进程通过if判断分流让子进程去跑了

  • 2.创建一个子进程不执行父进程的代码,而是让子进程在磁盘当中执行全新的程序,这种操作称之为进程的程序替换

2.了解程序是如何进行替换的

程序替换函数 execl
输入 man execl 查看程序替换接口

int execl(const char *path, const char *arg, …);
括号内部的 . . . 称为 可变参数列表,可以给c函数传递任意个数的参数
第一个参数为 要执行什么命令
第二个参数 为 要怎样执行程序
最后以NULL结尾表示参数传完了


创建test.c文件并输入以下内容

#include   #include  #include   int main()   {     printf("begin......\n");    printf("begin......\n");     printf("begin......\n");    printf("begin......\n");                         execl("/bin/ls", "ls", "-a", "-l", NULL);                    printf("end........\n");                    printf("end........\n");                    printf("end........\n");                   printf("end........\n");  }     

运行可执行程序发现,只有begin 以及执行 ls -l -a显示的指令


再次修改test.c文件内容如下

  #include   #include  #include   int main()   {     printf("begin......\n");    printf("begin......\n");     printf("begin......\n");    printf("begin......\n");     printf("我已经是一个进程啦,我的PID:%d\n",getpid());     execl("/bin/ls", "ls", "-a", "-l", NULL);                    printf("end........\n");                    printf("end........\n");                    printf("end........\n");                   printf("end........\n");  }       

test.c 经过编译形成mytest可执行程序,./可执行程序就变成进程了,CPU调度进程 ,打印出代码中的打印语句,同时调用程序替换execl,将ls程序执行起来了


[yzq@VM-8-8-Centos nn]$ file /bin/ls/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/linux 2.6.32, BuildID[sha1]=c8ada1f7095f6b2bb7ddc848e088c2d615c3743e, stripped

使用的 /bin/ls 命令 实际上是一个可执行程序,所以ls程序是在磁盘上的


前面执行的是自己代码的一部分,当调用execl时,将磁盘中可执行程序替换当前进程的代码和数据
后半部分就不执行自己的代码了,执行ls所对应的代码 ,这个现象就叫做程序替换

程序替换就是让一个进程去执行另一个在磁盘中的程序,让一个进程把一个新的程序运行起来

3. 程序替换的基本原理

在这里插入图片描述
当前的进程执行当前代码时,如果执行了函数execl等接口,就会根据你所传入的程序的路径以及你要执行的名称及选项,把磁盘当中的一个其他的程序加载到对应的内存,
用新程序的代码替换当前进程的代码段,用当前进程的数据替换老进程的数据段


站在进程的角度
进程的程序替换有没有创建新的进程呢?
没有,只是将新的程序加载到当前进程的代码段和数据段,用CPU去调度当前进程就可以跑起来了


站在程序的角度
程序被加载了内存中,就可以称程序替换的接口(execl) 为加载器

当创建进程的时候,先有进程数据结构,还是先加载代码和数据?

修改test.c文件为以下内容

#include  2    #include  3   #include  4    int main()  5    {  6        execl("/bin/ls", "ls", "-a", "-l", NULL);                          7   }

此时运行可执行程序,自己就写了一个ls命令


创建子进程,让子进程调用execl,在调用execl把代码和数据加载到内存
所以当创建进程的时候,先有进程数据结构,再加载代码和数据

程序替换是整体替换,不是局部替换

修改test.c文件内容如下

 #include  2    #include  3   #include  4 #include  5    int main()  6    {  7      pid_t id=fork();  8      if(id==0)  9      { 10        //child 11        printf("我是子进程:%d\n",getpid()); 12        execl("/bin/ls", "ls", "-a", "-l", NULL);                         13      }          sleep(5); 14      printf("我是父进程:%d\n",getpid()); 15      waitpid(id,NULL,0);                     16   }  

查看子进程完成替换后会不会影响父进程,如果影响父进程,就不应该打印父进程的这句话了


过了5秒钟,父进程结果打印出来,说明父进程不受子进程影响


程序替换只会影响调用进程,进程具有独立性
父子进程都有自己独立的PCB 地址空间 页表 也会自己的映射关系
虽然代码有可能是跟父进程共享,当子进程进行程序替换的时候,子进程会加载新进程的代码和数据
操作系统会发生写时拷贝,将代码和数据进行区分 ,使子进程形成新的映射关系,从而使子进程不会影响到父进程

execl 返回值

如果出错了,execl返回值为-1


修改test.c文件内容如下

#include  2    #include  3   #include  4 #include  5    int main()  6    {  7      pid_t id=fork();  8      if(id==0)  9      { 10        //child 11        printf("我是子进程:%d\n",getpid()); 12       int n=execl("/bin/lsss", "lsss", "-a", "-l", NULL);//lsss命令不存在      13        printf("you can see me:%d\n",n); 14        exit(0); 15      } 16      sleep(5); 17      printf("我是父进程:%d\n",getpid());     18      waitpid(id,NULL,0);             19   }      20      

输入的lsss命令不存在,查询报错后的execl的返回值


程序替换只要成功,就会跑去执行新程序,失败了就会继续向后运行
所以execl程序替换成功不会有返回值——>如果替换失败,一定有返回值——>如果失败了,必定返回——>只要有返回值就失败了
说明不用对execl函数的返回值进行判断,只要继续向后运行一定失败

4. 替换函数

1. execl

int execl(const char *path, const char *arg, …);
l 代表 list 链表
path:代表你想执行谁 (需要带路径)
执行一个程序最基本的原则为:找到它,加载执行它
arg:你想怎么执行它(若想执行ls指令,是只执行ls,还是执行ls- l 、ls -l -a指令
在命令行怎么执行这个命令,就把参数一个一个的传递给execl就可以了
最终以NULL结尾


具体的实现以及返回值问题上面在演示程序替换时已经使用过啦

2. execv

int execv(const char *path, char *const argv[]);
v代表vector 容器
path:代表你想执行谁 (需要带路径)
把原来需要一个一个传的参数放在argv[]数组


修改test.c文件内容

1    #include    2    #include    3   #include    4 #include    5    int main()    6    {    7      pid_t id=fork();    8      if(id==0)    9      {   10        //child   11        printf("我是子进程:%d\n",getpid()); 12        char *const myargv[]={"ls", "-l", "-a",NULL};13       execv("/bin/ls",myargv);   14        exit(0);   15      }   16      sleep(5);   17      printf("我是父进程:%d\n",getpid());   18      waitpid(id,NULL,0);   19   }   20                 

执行可执行程序,依旧可以执行ls指令

3. execlp

int execlp(const char *file, const char *arg, …);
带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找
file: 不需要传路径,只需要把在PATH环境变量的指令传过来
最后以NULL结尾


   #include    2    #include    3   #include    4 #include    5    int main()    6    {    7      pid_t id=fork();    8      if(id==0)    9      {   10        //child   11        printf("我是子进程:%d\n",getpid());   12        execlp("ls", "ls", "-l", "-a",NULL); 13        exit(0); 14      } 15      sleep(5);   16      printf("我是父进程:%d\n",getpid());       17      waitpid(id,NULL,0);                       18   }   

执行可执行程序,依旧可以执行ls指令


4. execvp

int execvp(const char *file, char *const argv[]);
带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找
v代表vector 容器


     #include         #include        #include      #include         int main()         {           pid_t id=fork();           if(id==0)           {             //child             printf("我是子进程:%d\n",getpid());           char* const myargv[]={"ls", "-l", "-a",NULL};             execvp("ls", myargv);             exit(0);           }           sleep(5);           printf("我是父进程:%d\n",getpid());           waitpid(id,NULL,0);                          }          

在这里插入图片描述

5. execle

int execle(const char *path, const char *arg,
…, char * const envp[]);
path:代表你想执行谁 (需要带路径)
envp[]:代表自定义环境变量
如果调用程序替换时,若不想让子进程使用父进程的环境列表,想自定义环境变量,就可以自己传一个环境变量


在另一个目录中创建other.cc (以cc为结尾说明是一个c++程序),并输入以下内容

#include     #include     #include    using namespace std;        int main()    {        for(int i = 0; i < 5; i++)        {          cout<< "我是另一个程序,我的pid是:"<< getpid()<

修改test.c文件为以下内容

     #include         #include        #include      #include         int main()         {           pid_t id=fork();           if(id==0)           {             //child             printf("我是子进程:%d\n",getpid());    W>       char*const myenv[]={"MYENV=YouCanSeeMe", NULL};             execle("/home/mydir/my/mm/myother", "myother", NULL,myenv);             exit(0);           }           sleep(1);           printf("我是父进程:%d\n",getpid());           int  status=0;           waitpid(id,&status,0);           return 0;        }   

在这里插入图片描述

第一个路径为other.cc生成的可执行程序 myother 所在的 绝对路径



2. 自定义shell

编写极简版本的shell(bash)
目标:为了深刻的理解shell的运行原理


输入 ps ajx |grep bash ,发现bash就是一个进程

在这里插入图片描述


由于shell是一个进程,所以用while死循环

缓冲区问题


在这里插入图片描述
正常来说,运行可执行程序会显示命令行,但是由于没有\n刷新缓冲区,也没有使用相关的刷新库函数,所以命令行会一直在缓冲区中 直到 程序结束才显示,但是这是个死循环,所以什么都不会显示


在这里插入图片描述


在这里插入图片描述


执行可执行程序后即可显示命令行

fgets 使用出现空格问题

fgets 标准输入 按行获取
char *fgets(char *s, int size, FILE *stream);
从特定的标准输入当中获取对应的命令行输入,把对应的数据放在缓冲区中




执行可执行程序后,发现在命令行中输入 ls -a ,就会打印出 ls -a,但是输入时会多出一个空行


在这里插入图片描述

正常来说,都会使用回车来到下一行,而这个回车被fgets读取到了


在这里插入图片描述
将最后的回车符替换成’\0’


在这里插入图片描述
此时就没有空格出现了

完整代码

: mybash.c ? ?                    ?? buffers   #include  #include  #include  #include  #include  #include  #include  #define MAX 1024  #define ARGC 64  #define SEP " "  int split (char*commandstr,char*argv[])  {      assert(commandstr);      assert(argv);      argv[0]=strtok(commandstr,SEP);//在commandstr以空格作为分割符      if(argv[0]==NULL)//切割失败      {        return -1;      }      int i=1;      while(1)      {       argv[i]=strtok(NULL,SEP);//继续切割空格       if(argv[i]==NULL)      {      break;       }       i++;               }W>}      void print(char*argv[])  { int i=0;    for(i=0;argv[i];i++)    {                     printf("%d:%s\n",i,argv[i]);    }  }  int main()  {        while(1)    {    char commandstr[MAX]={0};    char*argv[ARGC]={NULL};      printf("[yzq@mymachine currpath]# ");     fflush(stdout);    char*s= fgets(commandstr,sizeof(commandstr),stdin);    assert(s);    (void)s;//保证在release方式发布的时候,因为去掉assert了,所以s就没有被使用,而带来的编译告警, 什么都没做,但是充当一次使用    commandstr[strlen(commandstr)-1]='\0';//将最后的回车符用'\0'覆盖掉   int n= split(commandstr,argv); //从命令行中获取的字符串传入argv中     if(n!=0)       continue;//切割失败就什么都不做   // print(argv);//打印字符串    pid_t id=fork();      assert(id>=0);      (void)id;      if(id==0)      {        //child       execvp(argv[0],argv);        exit(1);     }      int status=0;       waitpid(id,&status,0);   }  }

动图演示

在这里插入图片描述

来源地址:https://blog.csdn.net/qq_62939852/article/details/129546632

--结束END--

本文标题: 【Linux】进程的程序替换

本文链接: https://lsjlt.com/news/377985.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 【Linux】进程的程序替换
    文章目录 1. 程序替换1.创建子进程的目的是什么?2.了解程序是如何进行替换的3. 程序替换的基本原理当创建进程的时候,先有进程数据结构,还是先加载代码和数据?程序替换是整体替换,不是局部替换execl 返回值 4. 替换函...
    99+
    2023-08-22
    linux 运维 服务器
  • Linux进程控制【进程程序替换】
    ✨个人主页: Yohifo 🎉所属专栏: Linux学习之旅 🎊每篇一句: 图片来源 🎃操作环境: CentOS 7.6 阿里云远程服务器 Good judgment comes fro...
    99+
    2023-08-22
    linux 运维 服务器 云原生 后端
  • 【Linux】Linux进程控制及程序替换
    🍎作者:阿润菜菜 📖专栏:Linux系统编程 进程控制及程序替换 进程创建fork的用法进程调用fork,内核做了什么fork函数的返回值问题fork创建失败的原因 进程等待进程等待是什么...
    99+
    2023-08-24
    linux 运维 服务器
  • Linux如何实现进程替换
    这篇文章将为大家详细讲解有关Linux如何实现进程替换,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Linux 进程替换(exec函数)实现代码  # include<...
    99+
    2023-06-09
  • C语言进程程序替换的实现详解
    目录进程程序替换替换原理替换函数替换函数名称助记进程程序替换 替换原理 使用fork创建子进程后执行的是和父进程相同的程序,但是那样并没有多大的意义,子进程往往会“程序替...
    99+
    2024-04-02
  • 【Linux】Linux进程控制 --- 进程创建、终止、等待、替换、shell派生子进程的理解…
    柴犬: 你好啊,屏幕前的大帅哥or大美女,和我一起享受美好的今天叭😃😃😃 文章目录 一、进程创建1.调用fork之后,内核都做了什么?2.如何...
    99+
    2023-09-08
    linux 运维 服务器
  • Linux 进程替换(exec函数)实现代码
    Linux 进程替换(exec函数)实现代码 # include<stdio.h> #include<stdlib.h> #include<unistd...
    99+
    2022-06-04
    函数 进程 代码
  • 《Linux从练气到飞升》No.20 Linux进程替换
     🕺作者: 主页 我的专栏C语言从0到1探秘C++数据结构从0到1探秘Linux菜鸟刷题集 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇码字不易,你的&#...
    99+
    2023-09-15
    linux java 服务器
  • Linux系统下的进程切换过程
    本篇内容介绍了“Linux系统下的进程切换过程”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Linux内核下进程切换Linux切换并没有使用...
    99+
    2023-06-13
  • 在Win32 程序中用 main() 函数替换 WinMain()
    在Win32程序中,可以使用main()函数替代WinMain()。首先,需要在程序的入口点函数main()中添加以下代码:```c...
    99+
    2023-09-26
    Win32
  • linux怎么查看java程序进程
    在Linux系统中,可以使用以下命令来查看Java程序的进程: 使用ps命令查看进程: ps -aux | grep java ...
    99+
    2024-03-14
    linux java
  • Linux使用sed命令替换字符串教程
    要替换字符串,我们需要使用以下格式。 $ sed s/替换的目标字符串/替换后的字符串/ 文件名 在下面我们替换写为“appleorangemelon”的字符串“sample.txt”。 $ sed s/ora...
    99+
    2022-06-04
    Linux sed
  • Linux 进程管理中如何进行调度和进程切换
    这篇文章将为大家详细讲解有关Linux 进程管理中如何进行调度和进程切换,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。什么是调度按照某种调度算法,从进程的ready队列中选择进程给CPU。为...
    99+
    2023-06-15
  • linux中进程与程序的区别有哪些
    这篇文章主要介绍“linux中进程与程序的区别有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“linux中进程与程序的区别有哪些”文章能帮助大家解决问题。linux中进程与程序的区别:1、程序是...
    99+
    2023-07-02
  • 【Linux】关于进程的理解、状态、优先级和进程切换
    文章目录 📝一、操作系统进程1.运行队列2.运行状态 📝二、Linux进程状态📝三、两个特殊进程1.僵尸进程2.孤儿进程 ...
    99+
    2023-09-06
    linux 服务器 运维
  • 【Linux】进程状态|优先级|进程切换|环境变量
    文章目录 1. 运行队列和运行状态2. 进程状态3. 两种特殊的进程僵尸进程孤儿进程 4. 进程优先级5. 进程切换进程特性进程切换 6. 环境变量的基本概念7. PATH环境变量8....
    99+
    2023-09-02
    linux 运维 服务器
  • C++中怎么使用exec()函数替换子进程的映像
    在C++中,可以使用exec()函数族来替换子进程的映像。下面是一个简单的示例代码: #include <iostream&g...
    99+
    2024-04-02
  • 怎么以正确的方式替换Go语言程序自身
    这篇文章主要介绍“怎么以正确的方式替换Go语言程序自身”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么以正确的方式替换Go语言程序自身”文章能帮助大家解决问题。Go语言是一门越来越受欢迎的编程语言...
    99+
    2023-07-06
  • Linux新手小程序——进度条
    前言 目录 前言 需要先了解        1.\r和\n                           2.缓冲区 一.理解字符的含义:         学习c语言时,我们可以粗略把字符分为可显字符和控制字符.         ...
    99+
    2023-08-31
    linux c++ c语言 小程序
  • android程序怎样进行语言切换
     首先创建多语言资源,参考 在MainActivity的onCreate()中添加如下代码  public void onCreate(Bund...
    99+
    2022-06-06
    Android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作