linux之进程管理(二)--替换

我们先来看一个现象

程序运行到execl这里的时候,去执行ls的命令行操作,但是并没有执行后面的代码,这是怎么回事呢???

这是我们正常的的一个进程

当我们运行execl这个函数的时候,将磁盘里面的数据加载到这个里面物理内存里面,将原来的代码和数据部分覆盖自然就看不到printf所打印出来的内容

在实践中,我们通常会让子进程来完成程序替换的过程

当父子进程都不对数据和代码修改时

当任意一方对数据发生修改时

调用程序替换函数时,将磁盘的文件加载到内存,覆盖子进程的代码和数据

至此彻底完成父子进程的分离

程序替换函数

cpp 复制代码
// 1. execl​
2int execl(const char *path, const char *arg0, ..., (char *)NULL);​
3// 2. execlp​
4int execlp(const char *file, const char *arg0, ..., (char *)NULL);​
5// 3. execle​
6int execle(const char *path, const char *arg0, ..., (char *)NULL, char *envp[]);​
7​
8// 4. execv​
9int execv(const char *path, char *const argv[]);​
10// 5. execvp​
11int execvp(const char *file, char *const argv[]);​
12// 6. execvpe​
13int execvpe(const char *file, char *const argv[], char *const envp[]);​
14​
15// 7. execve(真正系统调用,内核接口)​
16int execve(const char *path, char *const argv[], char *const envp[]);

|----|------------------------------|
| 字母 | 含义 |
| l | list,参数逐个罗列,最后必须 NULL |
| v | vector,参数放进字符串数组传参 |
| p | path,自动搜索环境变量 PATH,不用写完整绝对路径 |
| e | env,手动传入自定义环境变量数组 |

通用特性(全部 7 个函数一致)
  1. 成功永不返回,原程序代码全部被覆盖,后面代码不执行;

  2. 失败返回 -1,可 perror 打印错误;

  3. 不创建新进程,PID 不变,仅替换当前进程运行程序;

  4. 已打开的文件描述符默认继承(除非设置 FD_CLOEXEC)。

详细说明
execl
cpp 复制代码
// 1. execl
int execl(const char *path, const char *arg0, ..., (char *)NULL);
cpp 复制代码
 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/wait.h>
  4 #include<stdlib.h>
  5 int main()
  6 {
  7   printf("我是父进程,pid:%d\n",getpid());
  8   printf("========================================\n");                                                                                         
  9   pid_t id=fork();
 10   if(id==0){
 11     printf("下面是子进程执行的代码\n");
 12     execl("/bin/ls","ls","-l",NULL);
 13   }
 14   int status=0;
 15   pid_t rid=waitpid(-1,&status,0);
 16   if(rid>0)
 17   {
 18   printf("========================================\n");
 19     printf("成功回收子进程\n");
 20   }
 21   return 0;
 22 }
execlp
cpp 复制代码
// 2. execlp
int execlp(const char *file, const char *arg0, ..., (char *)NULL);
cpp 复制代码
if(id==0)
    {
      printf("下面是子进程执行的代码\n");
      execlp("ls","ls",NULL);                                                                                                                     
    }
execv
cpp 复制代码
// 4. execv
int execv(const char *path,  char *const argv[]);
cpp 复制代码
if(id==0)
   {
     printf("下面是子进程执行的代码\n");
     char *const argv[]= { "ls","-a","-l","--color=auto" ,NULL};                                                                               
     execv("/bin/ls",argv);
   }
execvp
cpp 复制代码
// 5. execvp
int execvp(const char *file, char *const argv[]);
cpp 复制代码
if(id==0)
      {
       printf("下面是子进程执行的代码\n");
      char *const argv[]= { "ls","--color=auto" ,NULL};                                                                                         
        execvp("ls",argv);
      }

在上面的案例中都是用系统的,那能不能用我们直接写的可执行文件呢???

显然是可以的

cpp 复制代码
if(id==0){
       printf("下面是子进程执行的代码\n");
       execl("./test/Replace.exe","Replace",NULL);                                                                                                
    }
execvpe
cpp 复制代码
// 6. execvpe
int execvpe(const char *file, char *const argv[], char *const envp[]);

e就是要我们手动传入环境变量和之前没有e的又有什么区别吗??

一个通俗比喻
  • 父进程手里有一整本资料(所有环境变量:PATH、HOME、USER......)

  • execvp(无 e):直接复印整本资料交给新程序

  • execvpe(有 e):旧资料作废,你亲手写一张新纸条交给新程序。 纸条上必须写上 PATH,否则新程序找不到 ls。

cpp 复制代码
if(id==0)
{
    printf("下面是子进程执行的代码\n");
    char *const argv[]= { "testEnviron.exe","-a","-c","6" ,NULL};
    char *envp[] ={"PATH=/home/pineapple/pineapple_dir/linux-learning/processReplace/test",NULL };
    extern char **environ;
    execvpe("./test/testEnviron.exe",argv,environ);
    //execvpe("./test/testEnviron.exe",argv,envp); 
    perror("execvpe 调用失败原因");               
    _exit(1);                                     
}

使用我们自己传入的环境变量

cpp 复制代码
if(id==0)
{
    printf("下面是子进程执行的代码\n");
    char *const argv[]= { "testEnviron.exe","-a","-c","6" ,NULL};
    char *envp[] ={"PATH=/home/pineapple/pineapple_dir/linux-learning/processReplace/test",NULL };
    execvpe("./test/testEnviron.exe",argv,envp); 
    perror("execvpe 调用失败原因");               
    _exit(1);                                     
}

在原来老的环境变量上面加上新的环境变量

cpp 复制代码
if(id==0)
{
    printf("下面是子进程执行的代码\n");
    char *const argv[]= { "testEnviron.exe","-a","-c","6" ,NULL};
    char *envp[] ={"PATH=/home/pineapple/pineapple_dir/linux-learning/processReplace/test",NULL };
    extern char **environ;
    putenv("PATH=/home/pineapple/pineapple_dir/linux-learning/processReplace/test");
    execvpe("./test/testEnviron.exe",argv,environ);

    // execvpe("./test/testEnviron.exe",argv,envp);
    perror("execvpe 调用失败原因");
    _exit(1);
}

剩下来大同小异,这里不做过多介绍.

相关推荐
倔强的石头1061 小时前
【Linux指南】动静态库系列(二):从源码复用到目标文件复用:为什么需要把 .o 打包成库
linux·运维·服务器
码农学院1 小时前
GEO与SEO协同:从传统搜索到生成式搜索的平滑迁移路径
服务器·前端·python
步步精BBJconn1 小时前
从GPU服务器到数据中心:AI服务器高压连接器的应用与发展趋势
大数据·运维·服务器·人工智能·科技·物联网
码农学院3 小时前
基于运维监控体系的网络品牌推广方案:从架构设计到技术实现
运维·网络
爱写代码的森10 小时前
鸿蒙三方库 | harmony-utils之ImageUtil图片保存到本地详解
服务器·华为·harmonyos·鸿蒙·huawei
大耳朵-小飞象12 小时前
电力安全运维的智能密码:BACS如何破解设备全生命周期管理难题,让电网安全“看得见、管得住”?
运维·安全·智慧城市·能耗系统·楼宇智控·未来生活
极客侃科技13 小时前
制造企业 MES/APS 选型:SAP PP/DS 集成、ERP-MES 边界划分与一体化架构要点
运维·架构·制造
HLC++13 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室14 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设