Linux_进程程序替换

进程程序替换

    1)替换原理

        用fork创建出子进程后执行的是和父进程相同的程序,可能执行的是不同的代码分支,子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行,调用exec并不创建新的进程,所以调用exec前后该进程的id并不改变。简单来说,替换的其实是程序的代码和数据,PCB还是那个PCB

    2) 替换函数(这些函数要加#include <unistd.h>头文件)

        1>函数原型 

          int execl(const char *path, const char *arg, ...);

          int execlp(const char *file, const char *arg, ...);

          int execle(const char *path, const char *arg, ..., char * const envp[]);

          int execv(const char *path, char *const argv[]);

          int execvp(const char *file, char *const argv[]);

扫描二维码关注公众号,回复: 2382774 查看本文章

          int execve(const char *path,char *const argv[],char * const envp[]);

        2>注意

            1}如果这些函数调用成功则加载新的程序从启动代码开始执行,不在返回原代码处。

            2}调用出错返回-1.

            3}exec函数只有出错的返回值,没有调用成功的返回值。

        3>函数命名理解

      不带字母p (表示path)的exec函数 第一个参数必须是程序的相对路径或绝对路径,例如"/bin/ls"或"./a.out",而不能 是"ls"或"a.out"。对于带字母p的函数: 如果参数中包含/,则将其视为路径名。 否则视为不带路径的程序名,在PATH环境变量的目录列表中搜索这个程序。
      带有字母l( 表示list)的exec函数要求将新程序的每个命令行参数都当作一个参数传给它,命令行参数的个数是可变的,因此函数原型中有...,...中的最后一个可变参数应该是NULL, 起sentinel的作用。
      带有字母v( 表示vector)的函数,则应该先构造一个指向各参数的指针数 组,然后将该数组的首地址当作参数传给它,数组中的最后一个指针也应该是NULL,就像main函数的argv参数或者环境变量表一样。

      对于以e (表示environment)结尾的exec函数,可以把一份新的环境变量表传给它,其他exec函数仍使用当前的环境变量表执行新程序。

        4>注意:替换的进程中内部命令执行不了。


举个例子

 #include <unistd.h>

 int main(void){
 execl("/bin/ls","ls","-l",NULL);
 return 0;
 }

运行结果:


execvp:有p的可以使用环境变量,无需写全路径

 #include <unistd.h>

 int main (void){
 char *const argv[]={"ls","-l",NULL};

 execvp("ls",argv);
 return 0;
 }

运行结果同上。

execve:

 #include <unistd.h>
 
 int main(void){
   char *const argv[]={"myenv",NULL};
   char *const envp[]={"mm=gg","hello","yes",NULL};
   execve("./myenv",argv,envp);
}

运行结果:


    4>原理:

        事实上,只有execve是真正的系统调用,其他5个函数都调用execve


下面通过几个进程替换函数实现一把简单的myshell


猜你喜欢

转载自blog.csdn.net/warrior_harlan/article/details/80542242