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

具体代码, 持续更新

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值