【Linux】进程的程序替换

本文详细解释了程序替换的基本原理,包括execl系列函数的用法,如如何执行新程序并替换当前进程,以及自定义shell的简要实现。讨论了进程替换过程中子进程与父进程的独立性和内存映射关系。
摘要由CSDN通过智能技术生成

1. 程序替换

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

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

具体做法:

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

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

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

3. 程序替换的基本原理

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

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

站在程序的角度
程序被加载了内存中,就可以称程序替换的接口(execl) 为加载器
程序替换只会影响调用进程,进程具有独立性
父子进程都有自己独立的PCB 地址空间 页表 也会自己的映射关系
虽然代码有可能是跟父进程共享,当子进程进行程序替换的时候,子进程会加载新进程的代码和数据
操作系统会发生写时拷贝,将代码和数据进行区分 ,使子进程形成新的映射关系,从而使子进程不会影响到父进程

execl 返回值
如果出错了,execl返回值为-1
程序替换只要成功,就会跑去执行新程序,失败了就会继续向后运行
所以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结尾

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

  1. execv
    int execv(const char *path, char *const argv[]);
    v代表vector 容器
    path:代表你想执行谁 (需要带路径)
    把原来需要一个一个传的参数放在argv[]数组中
  2. execlp
    int execlp(const char *file, const char *arg, …);
    带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找
    file: 不需要传路径,只需要把在PATH环境变量的指令传过来
    最后以NULL结尾
  3. execvp
    int execvp(const char *file, char *const argv[]);
    带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找
    v代表vector 容器
  4. execle
    int execle(const char *path, const char *arg,
    …, char * const envp[]);
    path:代表你想执行谁 (需要带路径)
    envp[]:代表自定义环境变量
    如果调用程序替换时,若不想让子进程使用父进程的环境列表,想自定义环境变量,就可以自己传一个环境变量

2. 自定义shell

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

: mybash.c ? ?                                                                                                                                                                ?? buffers 
  #include<stdio.h>
  #include<unistd.h>
  #include<string.h>
  #include<assert.h>
  #include<sys/types.h>
  #include<sys/wait.h>
  #include<stdlib.h>
  #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);
   }
  }


  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值