linux下的进程程序替换

2023-12-13 10:43:18

替换概念

当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的代码部分开始运行。调用exec并不创建新的进程,所以调用exec前后该进程的id并未改变。

大概意思就是程序替换只是把程序换了,仅仅是从1号程序换到了2号程序,修改了页表的映射地址,但是并没有创建新的PCB,因此没有创建新的进程。
这就是进程替换的概念!
在这里插入图片描述

替换函数

在linux手册里,有6个相似的函数,他们虽然参数列表不一样,但是功能一样。
在这里插入图片描述

  • 如果这些函数调用成功则加载新的程序,从启动代码开始执行,不再返回。
  • 如果出错则返回-1。
  • 所以exec函数只有出错的返回值而没有成功的返回值。

execl()

l:列表的形式传入参数

int extcl(const char * path, const char* argv,…);
参数:
path:是要打开可执行程序的路径
argv,… :这个语法表示可变的参数列表,可以传入多个不定个数的参数,最后一个参数传入NULL,表示参数传递完成。

描述不清楚,看个例子就明白了:

  1 #include<stdio.h>
  2 #include<unistd.h>

  5 int main()
  6 {
  7   printf("当前进程开始!\n");
  8   //execl("/usr/bin/ls","ls","--color=auto","-l",NULL);
  9   //一旦调用成功,后续代码都不会执行了!!!                                                                                                                            
 10   execl("/usr/bin/ls","ls","--color=auto","-l", "-i",NULL);
 11   //execl("/usr/bin/top", "top", NULL);
 12   printf("当前进程结束!\n");                                                                                                                                   
 13   return 0;                                                                                                                                                     
 14 }      

因为Linux系统下一切皆文件,ls命令其实就是一个可执行程序,我们使用execl函数,执行这个程序。我们可以改变可变参数列表来使用ls命令不同的功能。
在这里插入图片描述

execv()

v:数组的形式传入参数

int extcv(const char * path, char *const argv[]);
参数:
path:仍然是文件路径。
char *argv[]:指针数组,以数组的形式传入。

为了更加适应实际的应用场景,我们使用父进程fork子进程,然后使用子进程进行进程替换,这样不会影响父进程的执行。
如下:

7 #define NUM 32
  8 int main()
  9 {
 10   pid_t id = fork();
 11 
 12   if(id == 0)
 13   {
 14     //子进程
 15     // ls -a -l
 16     printf("子进程开始执行,pid = %d \n",getpid());
 17     //传入指针数组
 18     char *const _argv[NUM] = {
 19      (char*)"ls",
 20      (char*)"-l",
 21       (char*)"-i",
 22       NULL
 23     };
 24     execv("/usr/bin/ls",_argv);  //传入指针数组!!!
 25     exit(1);
 26   }
 27   else{
 28     //父进程
 29     printf("父进程开始等待,pid =%d \n", getpid());                                                                                                                     
 30     int status = 0;
 31     pid_t ret = waitpid(-1, &status, 0); //阻塞等待
 32     if(ret>0)
 33     {
 34       printf("等待成功,退出码为:%d \n", WEXITSTATUS(status));
 35     }
 36   }
 37   return 0;
 38 }

在这里插入图片描述
可以看到,子进程帮助父进程完成了执行ls命令,并且没有影响父进程的执行。

execvp()/execlp()

p:表明第一个参数不再是文件路径,而是通过环境变量就可以找到的程序。
看下面的例子更能清楚的解释:

execvp()的例子:

  7 #define NUM 32
  8 int main()
  9 {
 10   pid_t id = fork();
 11 
 12   if(id == 0)
 13   {
 14     //子进程
 15     // ls -a -l
 16     printf("子进程开始执行,pid = %d \n",getpid());
 17     //传入指针数组
 18     char *const _argv[NUM] = {
 19      (char*)"ls",  
 20      (char*)"-l",  
 21       (char*)"-i",  
 22       NULL  
 23     };  
 24     //execv("/usr/bin/ls",_argv);  
 25     execvp("ls",_argv);   //因为环境变量的存在,我们可以只输入ls便可找到该文件。                                                                                        
 26     exit(1);                                             
 27   }                                                                                                                              
 28   else{                                                                                                                          
 29     //父进程                                                                                                                     
 30     printf("父进程开始等待,pid =%d \n", getpid());                                                                              
 31     int status = 0;                                                                                                              
 32     pid_t ret = waitpid(-1, &status, 0); //阻塞等待                                                                              
 33     if(ret>0)                                                                                                                    
 34     {                                                                                                                            
 35       printf("等待成功,退出码为:%d \n", WEXITSTATUS(status));                                                                   
 36     }                                                                                                                            
 37   }                                                                                                                              
 38   return 0;
 39 }

在这里插入图片描述

execlp()例子:
仅仅将上面的代码,25行换成26行的内容即可!

   25     //execvp("ls",_argv);   //因为环境变量的存在,我们可以只输入ls便可找到该文件。                                                                   
   26     execlp("ls", "ls", "-l", "-i", NULL);        

execle()/execvpe()

e:可以维护自己的环境变量,将环境变量传给要替换的进程。

以execle为例:
将上面的子进程调用部分修改:

    7 #define NUM 32
    8 int main()
    9 {
   10 
   11   //设置一个环境变量,为的是 让子进程拿到
   12   //因为环境变量具有全局属性
   13   char *const _env[NUM]={
   14     (char*)"xty=123456789",
   15     NULL
   16   };

   31     execle("./myexe", "mycmd", "-a", NULL, _env);   //修改成这样,//其中列表参数是随便传的,myexe是调用的可执行程序。
myexe:
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 
  4 int main()
  5 {
  6                                                                                                                                                                         
  7   printf("得到的环境变量xty:%s\n", getenv("xty"));
  8   return 0;
  9 }

在这里插入图片描述

可知myexe获取到了环境变量。

如何在C/C++程序里面执行别的语言写的程序。

在这里插入图片描述

//使用这个命令即可运行
python test.py

在这里插入图片描述

首先写一个python文件脚本。待会我们就是用c程序执行它。
使用execlp()调用比较合适。

  1 #include <stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>
  6 int main()
  7 {
  8   pid_t id = fork();
  9   if(id == 0)
 10   {
 11     //子进程,调用别的语言写的程序
 12     execlp("python", "python", "test.py", NULL);
 13     exit(-1);
 14   }
 15   else{
 16     //父进程
 17     int status = 0;
 18     printf("父进程开始等待: \n");
 19     int ret = waitpid(-1, &status, 0); //阻塞等待
 20     if(ret > 0)
 21     {
 22       printf("父进程等待成功,子进程退出码为:%d \n",WEXITSTATUS(status));
 23 
 24     }
 25   }                                                                                                                                                                     
 26   return 0;
 27 }

在这里插入图片描述
我们可以看出python脚本被我们成功调用!

小tips

我们在运行py脚本时,需要运行python这个程序。因为python是一个解释器,我们需要使用解释器来解释test.py文件。

python test.py

如果我们给该test.py文件加上执行(x)权限,那么我们这样即可运行该文件:

在这里插入图片描述

因此将上面的execlp调用参数,修改为下面这样也可以:

 //12     execlp("python", "python", "test.py", NULL);
 12     execlp("./test.py", "test.py", NULL);

上面就是程序替换的相关知识,更深入的内容还请读者自行查阅和学习。

文章来源:https://blog.csdn.net/weixin_45153969/article/details/134846223
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。