Linux 进程程序替换

目录

进程程序替换

         进程替换的原理

替换函数exec族函数

1. execv(参数格式是数组)

2.execl(参数格式是列表)

3.execvp / execlp(不带替换程序的路径)

4.execle / execve(需要自己设置环境变量) 


相关博客:

进程相关概念: 戳链接( ̄︶ ̄)↗https://blog.csdn.net/qq_41071068/article/details/103213364
进程创建(fork):戳链接( ̄︶ ̄)↗https://blog.csdn.net/qq_41071068/article/details/103302804
进程退出:戳链接( ̄︶ ̄)↗https://blog.csdn.net/qq_41071068/article/details/103302874
进程等待(wait()/waitpid()):戳链接( ̄︶ ̄)↗https://blog.csdn.net/qq_41071068/article/details/103302883

进程程序替换

为什么要进行进程替换 ?

前面说到,  fork()创建子进程, fork创建的子进程要么和父进程执行一样的代码, 要么执行不同的代码分支(通过fork的返回值控制),

但这样还是不够灵活. 假如要有很多的功能已经用别的程序实现好了, 那么就不需要在父进程中控制父子进程执行不同的代码分

支, 让子进程在自己的分支中完成这些功能, 而是可以直接拿一个已有的程序替换掉子进程. 使子进程的代码完全变成所替换程序

的代码. 这样就方便了很多, 而且在子进程需要完成较为复杂的功能或是多项功能时, 分支就显得力不从心了.

所以进程往往要调用exec族中的某一个函数来进行程序替换, 让一个进程来执行另一个程序. 当进程调用一种exec函数时,该进程

的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec族中的函数并不会创建新进程,所以调用exec

前后被替换进程的iD并未改变。

进程替换的原理

如上图, 进程替换时, 替换的是PCB映射在内存中的代码和数据. 这样, 该进程PID虽然没有变, 但已经物是人非, 已经不是原来的那

个进程了.

如进行进程程序替换? 前面也说到了, exec族函数

替换函数exec族函数

exec族函数共有六个, 功能都是进程程序替换, 但多个不同的函数接口使得使用更加灵活. 

其中exceve()是系统调用接口, 其余5个底层都封装了execve().

函数原型如下 :

int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg0, ... /*,(char *)0, char *const envp[]*/);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
int execvp(const char *file, char *const argv[]);

头文件: unistd.h 

返回值 :

  • 这六个函数返回值相同. 
  • 当函数调用失败, 返回 -1. 
  • 当调用成功, 即加载新的程序, 替换后的进程启动开始执行,exec族函数不再返回 .
  • 特殊的地方是, 函数调用成功, 不返回

参数:

虽然有六个, 不好记, 但好在有规律. 可以发现, 函数名都是在exce的基础上, 加上l, v, e,  p形成新的函数名, 加哪个字母都有各自的

含义 , 如下所示:

  • l / v 必须有一个, 也只能有一个, 带l参数格式是列表,  带 v 参数格式是 数组 
  • p   有p, 会自动搜索环境变量PATH, 则可以不带路径, 只要文件名(但文件必须放在PATH环境变量指定路径).  没有p, 则必须指定文件路径
  • e    有e, 则不使用当前环境变量, 需要自己设置环境变量,  没带e, 则使用当前环境变量, 无需设置环境变量

如下表:

函数名 参数格式 函数是否自带路径(通过PATH) 是否使用当前环境变量
execl 列表 不带, 需要制定文件路径 使用
execlp 列表 带, 但文件必须的放在指定目录 使用
execle 列表 不带, 需要制定文件路径 不使用, 需要自己设置环境变量
execv 数组 不带, 需要制定文件路径 使用
execvp 数组 带, 但文件必须的放在指定目录 使用
execve 数组 不带, 需要制定文件路径 不使用, 需要自己设置环境变量

来看一下这六个函数具体如何使用.

1. execv(参数格式是数组)

#include<stdio.h>
#include<unistd.h>
int main() {
    char* arg[] = {"ls","-a","-l","/",NULL };//参数数组;//参数数组
    execv("/bin/ls", arg);
    printf("hello world!\n");
    return 0;
}

 可以看到进程被ls程序替换后, 只会执行ls的代码, 并不会再输出 hello world!

 如下, 还可以通过main函数的参数传入, 我们用Shell调用ls等命令就是这个原理.

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc, char* argv[]){
    char* arg[] = {"ls","-a","-l",NULL };//参数数组
    pid_t pid = fork();
    if(pid == -1){
        perror("fork");
    }
    else if(pid == 0){
        printf("替换子进程\n");
        execv("/bin/ls", argv);
    }
    else{
        sleep(1);
        printf("替换父进程\n");
        execv("/bin/ls", arg);
    }
    printf("hello world!\n");
    return 0;
}

 

2.execl(参数格式是列表)

#include<stdio.h>
#include<unistd.h>
int main(){
    execl("/bin/ls", "ls", "/", NULL);
    printf("hello world!\n");
    return 0;
}

3.execvp / execlp(不带替换程序的路径)

execvp

#include<stdio.h>
#include<unistd.h>
int main(int argc, char* argv[]){
    execvp("ls", arg);
    printf("hello world!\n");
    return 0;
}

 execlp

#include<stdio.h>
#include<unistd.h>
int main(){
    char* arg[] = {"ls","-a","-l",NULL };//参数数组
    execlp("ls", "-a", "-l", NULL);
    printf("hello world!\n");
    return 0;
}

 

4.execle / execve(需要自己设置环境变量) 

execve

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc, char* argv[]){
    char* envp[] = {"PATH=/home/test", NULL};
    execve("/bin/env", argv, envp);
    return 0;
}

execle

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(){
    char* envp[] = {"PATH=/home/test", NULL};
    execle("/bin/env", "", NULL, envp);
    return 0;
}

学习完进程的创建和替换后, 就可以利用这些知识, 写一个自己的Shell了

进程的创建在另一篇博客, 戳链接( ̄︶ ̄)↗https://blog.csdn.net/qq_41071068/article/details/103302804

具体代码, 持续更新

发布了223 篇原创文章 · 获赞 639 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_41071068/article/details/103319828