程序替换
程序替换是指替换一个正在运行中的程序.
我们知道, linux中进程就是一个pcb, 是对一个运行中程序的描述, 通过虚拟地址空间及页表, 将程序运行对应的数据及代码映射到物理内存, 程序替换就是pcb不变, 但是映射到物理内存的代码和数据改变成另一个程序.
那么, 如何去理解程序替换呢?
我们可以这样去思考, 当我们使用 fork()创建子进程之后, 子进程执行的是和父进程相同的程序(先不考虑根据返回值进行代码分流), 这个时候, 我们就可以在子进程当中调用exec函数来执行其他的程序, 如果这个程序出了问题奔溃掉也不会影响父进程, 没有问题则帮助我们完成其他的任务.
exec函数族相关函数介绍
execl(char* path, char* arg, ...);
execv(char* path, char* argv[]);
execlp(char* filename, char* arg, ...);
execvp(char* filename, char* argv[]);
execle(char* path, char* arg, ..., char* env[]);
execve(char* filename, char* argv[], char* env[]);
//这些函数运行成功的时候是没有返回值的, 因为跑去运行其它程序了
//若有返回值的话, 只能是程序替换失败, 返回-1
关于exec函数族的理解
-
l和v的区别
新程序的运行参数赋予方式不同//程序替换运行 ls -l, 直接将新程序运行所需要的参数以不定参的形式传入, 并以NULL作为结束 execl("/bin/ls", "ls", "-l", NULL); //程序替换运行 ls -l, 将新程序运行所需要的参数通过字符串指针数组的形式传入, 数组中依然以NULL作为结束表示 char* argv[] = {"ls", "l", "NULL"} execv("/bin/ls", argv);
-
有没有p的区别
新程序的名称是否需要带路径//带p不需要指定路径 execlp("ls", "ls", "-l", NULL); char* argv[] = {"ls", "l", "NULL"} execvp("ls", argv); //注意, 带p虽然可以不用指定路径, 但是程序必须在PATH环境变量指定的路径下
-
有没有e的区别
新运行的程序是否需要重新自定义环境变量, 带e的自定义环境变量, 不带e使用当前进程默认的环境变量//自己定义的环境变量 char *env[3] = {NULL}; env[0] = "MYVAL=1000"; env[1] = NULL; execle("ls", "ls", "-l", NULL); char* argv[] = {"ls", "l", "NULL", env} execve("ls", argv, env);
利用程序替换实现一个简单的minishell
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
while(1) {
//增加一个类似于shell的提示
printf("[MineMinishell]$ ");
fflush(stdout);//刷新标准输出缓冲区,不用等到程序结束才打印提示
//等待标准输入
char buf[1024] = {0};
fgets(buf, 1023, stdin);
buf[strlen(buf)-1] = '\0'; //注意这里是把最后接收到的换行符置为'\0'
char *argv[32] = {NULL};
int argc = 0;
char *ptr = buf;
//对接收到的命令字符串进行解析
while(*ptr != '\0') {
if (*ptr != ' ') {
argv[argc] = ptr;
argc++;
while(*ptr != ' ' && *ptr != '\0') {
ptr++;
}
*ptr = '\0';
}
ptr++;
}
argv[argc] = NULL;//最后一个参数的下一个位置置NULL
//创建子进程
pid_t pid = fork();
if (pid == 0) {
//在子进程中程序替换
execvp(argv[0], (char**)argv);//程序替换成功就去运行新程序
perror("execvp error");//运行到这一步表示程序替换失败了
exit(0);
}
wait(NULL);//进程等待,等待子进程退出,回收子进程资源
}
return 0;
}