子进程创建后,与父进程干同样的事情,通过fork的返回值进行分流,可以让子进程干自己的事,但是这样程序的耦合度非常强,因为所有代码都是在当前程序中编写的,如果想要改变子进程功能处理流程,需要修改整个程序代码,然后重新进行编译,这样一来,我们的程序就会变得非常大,为了解决这一问题,我们引入程序替换。
进程替换:替换一个进程正在运行的程序,让当前进程pcb调度运行管理另一个新的程序。本质来说就是替换一个PCB在内存中对应的代码和数据,加载另一个程序到内存中,然后更新页表信息,初始化虚拟地址空间。
替换原理: 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。 即:将一个新的程序加载到内存中,修改当前进程pcb的页表信息(还会初始化虚拟地址空间),让这个页表映射到新的程序上,这样就实现了pcb还是原来的pcb(进程id没有改变),但是运行的程序成为新的程序。新的程序的运行是从起始main函数开始运行的。
替换函数(exec函数族): 1)int execl(const char *path,const char *arg,···); path:新的程序路径名称,通过这个路径将一个新的程序加载到内存中,让当前的pcb去调度这个程序的运行,即使用这个程序替换正在调度运行的程序 arg/···:将程序的运行参数通过不定参的形式传递进入新的程序;最后以NULL作为结尾 2)int execlp(const char *file,const char *arg,···) 3)int execle(const char *path,const char *arg,···,char *const envp[]); 4)int execv(const char *path,char *const argv[]); 5)int execvp(const char *file,char *const argv[]); 6)int execve(const char *path,char *const argv[],char *const envp[]);
[ 前五个为库函数,最后一个为系统调用接口 ]函数解释 1)这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回 2)如果调用出错则返回-1 3)所以exec函数只有出错的返回值而没有成功的返回值
命名理解 1)l(list):表示参数采用列表 2)v(vector):参数用数组 3)p(path):有p自动搜索环境变量PATH 4)e(env):表示自己维护环境变量 l和v的区别:程序运行参数的赋予方式不同,l通过不定参完成,v通过字符串指针数组进行赋予 有没有p的区别:第一个参数执行新程序的时候是否需要带路径,有p则可以不用带路径,默认回去PATH环境变量指定的路径下查找 有没有e的区别:这个进程的环境变量是否需要初始化,有e表示初始化,没有e表示使用默认的环境变量
代码测试
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main(int argc,char *argv[]) { printf("hello\n"); //execl("./mytest","ls","-l",NULL);//对当前调用进程进行程序替换,运行mytest程序,参数通过 不定参形式赋予 //execl("替换程序路径","第0个参数:替换程序本身","参数1:-l",NULL)//以NULL结尾 char *new_argv[]={"mytest","-l","-p",NULL};//参数通过字符串指针数组赋予 //execv("./mytest",new_argv); //execvp("./mytest",new_argv);//运行当前路径下的mytest char *new_env[]={"MYVAL=1000","TESTVAL=2000",NULL}; execve("./mytest",new_argv,new_env); return 0; } #include<stdio.h> #include<unistd.h> #include<stdlib.h> int main(int argc,char *argv[],char *env[]) { //argc 这个main函数的第一个参数,用于表示当前程序有多少个运行参数 //argv 这个字符串指针数组用于存储当前程序的运行参数 int i; for(i=0;i<argc;i++){//也可以写成(i=0;argv[]!=NULL;i++) printf("argc[%d]=[%s]\n",i,argv[i]); } for(i=0;env[i]!=NULL;i++){ printf("env[%d]=[%s]\n",i,env[i]); } return 0; }