成都网站建设scdzks,宣城网站 建设,wordpress分享小图片不,手机优化电池充电要开吗进程替换1.什么是进程替换2.替换函数2.1 execl函数2.2 execv函数2.3 execlp函数2.4 execvp函数2.5 在自己的C程序上如何运行其他语言的程序#xff1f;2.6 execle 函数2.7 小结3.一个简易的shell1.什么是进程替换
fork()之后#xff0c;父子各自执行父进程代码的一部分…
进程替换1.什么是进程替换2.替换函数2.1 execl函数2.2 execv函数2.3 execlp函数2.4 execvp函数2.5 在自己的C程序上如何运行其他语言的程序2.6 execle 函数2.7 小结3.一个简易的shell1.什么是进程替换
fork()之后父子各自执行父进程代码的一部分父子代码共享数据写时拷贝各自一份如果子进程想就执行一个全新的进程呢 进程的程序替换来完成这个功能。 程序替换是通过特定的接口加载磁盘上的一个权限的程序代码和数据加载到进程的地址空间中。 用fork创建子进程后执行的是和父进程相同的程序但有可能执行不同的代码分支子进程往往要调用一种exex函数以执行另外的一个程序。当进程调用一种exec函数时该进程的用户空间代码和数据完全被新进程替换从新程序的启动例程开始执行。调用exec并不创建新进程所以调用exec函数前后进程的id并未改变。 所以进程替换并没有创建新的子进程所谓的exec*函数本质就是加载程序的函数。
2.替换函数
*exec 函数**功能其实就是加载器的底层接口
2.1 execl函数 1 #include stdio.h2 #include unistd.h3 4 5 int main()6 {7 printf(当前进程的开始代码\n);8 9 // execl(/usr/bin/ls,ls,NULL);10 // execl(/usr/bin/ls,ls,-l,NULL);11 execl(/usr/bin/ls,ls,-l,--colorauto,-a,NULL); 12 printf(当前进程的结束代码\n); 13 14 return 0; 15 }
运行结果
[jyfVM-12-14-centos 进程]$ ./mytest11
当前进程的开始代码
. Makefile myproc.c mytest10 mytest2 mytest4 可见并没有执行printf(“当前进程的结束代码\n”);这条语句进程发生了替换。 execl是程序替换调用该函数成功之后会将当前进程的所有代码和数据都进行替换包括已经执行的和没有执行的所以一旦调用成功后续的所有代码都不会执行。
进程替换应用实例 1 #include stdio.h2 #include stdlib.h3 #include unistd.h4 #include sys/wait.h5 6 int main()7 {8 //为什么我要创建子进程9 //如果不创建我们替换的进程就是父进程如果创建了我们替换的进程就是子进程而不影响父进程。10 //因为我们想让父进程聚焦在读取数据解析数据指派进程执行代码的功能 11 12 //1.显示一个提示符rootlocalhost# 13 //2.获取用户输入的字符串fgets,scanf,- ls -a -l14 //3.对字符串进行解析15 while(1) 16 { 17 pid_t id fork();18 if(id 0) 19 { 20 //子进程 21 printf(子进程开始运行pid:%d\n,getpid());22 sleep(3); 23 execl(/usr/bin/ls,ls,-a,-l,NULL);24 exit(1); 25 } 26 else{ 27 ;//父进程 28 printf(父进程开始运行%d\n,getpid()); 29 int status 0; 30 pid_t id waitpid(-1,status,0);//阻塞等待一定是子进程先运行完毕然后父进程获取之后才退出31 if(id0) 32 { 33 printf(wait success,exit code:%d\n,WEXITSTATUS(status));34 } 35 } 36 } 37 return 0;38 }
加载新程序之前父子进程的代码和数据的关系代码共享数据写时拷贝。 当子进程加载新程序的时候不就是一种写入吗代码要不要写时拷贝呢将父子进程的代码分离必须分离。 int execl(const char* path,const char* arg,…); 父子进程在代码和数据上就彻底分开了虽然曾经并不冲突。
2.2 execv函数 代码如下
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/wait.h int main()
{ pid_t id fork(); if(id 0) { printf(子进程开始运行:%d\n,getpid()); char* const _argv[] {(char*)ls,(char*)-a,(char*)-l,NULL}; execv(/usr/bin/ls,_argv); exit(1); } else { printf(父进程开始运行:%d\n,getpid()); int status 0; pid_t id waitpid(-1,status,0); if(id0) { printf(wait success,exit code:%d\n,WEXITSTATUS(status)); } } return 0;
} 运行结果
[jyfVM-12-14-centos lesson3-28]$ ./mytest
父进程开始运行:26522
子进程开始运行:26523
total 36
drwxrwxr-x 2 jyf jyf 4096 Mar 28 22:45 .
drwx------ 19 jyf jyf 4096 Mar 28 17:26 ..
-rwxrwxr-x 1 jyf jyf 8616 Mar 28 22:45 mytest
-rwxrwxr-x 1 jyf jyf 8616 Mar 28 21:57 mytest1
-rw-rw-r-- 1 jyf jyf 532 Mar 28 22:45 test1.c
wait success,exit code:0
2.3 execlp函数 要执行程序必须先找到程序带路径不带路径都能找到吗只要在环境变量中存在即可。 我会自己在环境变量PATH中进行查找你不用告诉我你要执行的程序在哪里
2.4 execvp函数
// int execvp(const char *file, char *const argv[]);
execvp(ls,_argv);
const char* file:具体要执行的程序它会到环境变量里面去找 具体实施方法如execv函数。
2.5 在自己的C程序上如何运行其他语言的程序 #include stdio.h #include stdlib.h #include unistd.h #include sys/wait.h const char* myfile /home/jyf/lesson3-28/mycmd; int main() { pid_t id fork(); if(id 0) { printf(子进程开始运行:%d\n,getpid());
W char* const _argv[] {(char*)ls,(char*)-a,(char*)-l,NULL}; // execv(/usr/bin/ls,_argv); //execlp(ls,ls,-a,-l,NULL); //execvp(ls,_argv); //execl(myfile,mycmd,-a,NULL); //execlp(python,python,test.py,NULL); //运行python程序 //execl(/usr/bin/python,python,test.py,NULL); //运行python程序execlp(bash,bash,test.sh,NULL); //运行shell程序 exit(1); } else { printf(父进程开始运行:%d\n,getpid()); int status 0; pid_t id waitpid(-1,status,0); if(id0) { printf(wait success,exit code:%d\n,WEXITSTATUS(status)); } } return 0; } 2.6 execle 函数
int execle(const char *path, const char *arg, ..., char * const envp[]);
char* const envp[ ]:将环境变量传递给要替换的程序
2.7 小结 命名理解这些函数看起来很容易混但只要掌握规律就很好记。 l(list):表示参数要自己给具体路径 v(vector):表示可变参数都放到数组中 p(path):有p自动在环境变量中搜索PATH e(env):表示自己创建维护环境变量将环境变量传递给要替换的进程
为什么要替换 一定和应用场景有关我们有时候必须让子进程执行新的程序
3.一个简易的shell #include stdio.h #include stdlib.h#include unistd.h#include sys/wait.h#include sys/types.h#include string.h#define NUM 1024#define SIZE 32#define SEP //保存完整的命令行字符串char cmd_line[NUM];//保存打散之后的命令行字符串char* g_argv[SIZE];//shell 运行原理父进程读取命令解析命令派发给子进程命令让子进程去执行命令int main(){//0.命令行解释器一定是一个常驻内存的进程不退出while(1){//1.打印出提示信息[rootlocalhost myshell]#printf([rootlocalhost myshell]# );fflush(stdout);memset(cmd_line,\0,sizeof(cmd_line));//2.获取用户的键盘输入[输入的是各种指令和选项: ls -a -l -i]if(fgets(cmd_line,sizeof(cmd_line),stdin) NULL){continue;}cmd_line[strlen(cmd_line)-1] \0;//将回车键\n,替换成\0//ls -a -l -i\n\0// printf(echo %s\n,cmd_line);g_argv[0] strtok(cmd_line,SEP);//将输入的字符串按空格进行分割第一次调用要传入原始字符串int index 1;if(strcmp(g_argv[0],ls) 0) //ls自带调色实现{
W g_argv[index] --colorauto;}if(strcmp(g_argv[0],ll) 0) //ll命令的简写的实现{
W g_argv[0] ls;
W g_argv[1] -l;
W g_argv[2] --colorauto;index2;}
W while(g_argv[index] strtok(NULL,SEP));//第二次调用如果还要解析原始字符串传入NULL//for debug//for(index 0;g_argv[index];index)//{//procrintf(g_argv[%d]: %s\n,index,g_argv[index]);//}//4.TODO,内置命令让父进程自己执行的命令我们叫内置命令内建命令//内建命令本质其实就是shell中的一个函数调用if(strcmp(g_argv[0],cd) 0) //not child execute ,father execute{if(g_argv[1]!NULL){chdir(g_argv[1]); //cd path}continue;}//5.fork()pid_t id fork();if(id 0){//procrintf(下面功能让子进程进行的\n);execvp(g_argv[0],g_argv); exit(1);}}//fatherint status 0;pid_t ret waitpid(-1,status,0);if(ret0){//printf(exit code:%d\n,WEXITSTATUS(status));}}return 0;}