1.代码看现象
#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/wait.h> int main() { printf("test begin\n"); int id=fork();//产生子进程 if(id==0) {sleep(2); execl("/usr/bin/ls","ls","-l","-a",NULL);//子进程替换ls进程 exit(1);//如果走到这里说明替换失败//替换失败的原因可能是因为无该进程 } int status=0; int reid=waitpid(id,&status,0);//阻塞等待子进程的状态,等待回收资源 if(reid>0)//说明子进程资源已经回收,子进程的进程号>0 { printf("father wait success,child exit code:%d\n",WEXITSTATUS(status));//子进程的退出码 } printf("test end\n"); return 0; }
1.疑问
为什么这里的退出码是0,不是1呢?
原因是由于子进程被替换成ls进程后,旧的子进程后面就不执行了,所以exit(1)这句代码就不会执行,而是执行新进程ls,而进程ls执行成功,所以退出码为0.
验证:
我们可以通过改变要替换的子进程不存在,就不会替换子进程,所以退出码会是1
2.execl函数参数分析
总结:1.execl函数,可以执行起来新的程序
2.execl函数,执行完毕后,后续的代码不见了,因为被替换了
3.execl函数的返回值可以不用关心,只要替换成功了,就不会往后继续进行了,只要继续运行了,一定是替换失败了
2.解释原理
3.进程替换(c替换c++)
子进程要替换的cpp程序
include<iostream> #include<unistd.h> #include <sys/types.h> using namespace std; int main() { cout<<"this is c++"<<getpid()<<endl; cout<<"this is c+"<<getpid()<<endl; cout<<"this is c++"<<getpid()<<endl; cout<<"this is c++"<<getpid()<<endl;
由于要编译两个程序,所以写个makefile来进行编译
.PHONY:all all:exe exe1 exe:test.c gcc -o exe test.c exe1:ans.cc g++ -o exe1 ans.cc -std=c++11 .PHONY:clean rm -rf exe exe1
在makefile里面他只会默认给第一个依赖列表通过依赖方法形成目标文makefile/make会自动根据文件中的依赖关系,进行自动推导,帮助我们执行所有相关的依赖方法.
test.c修改
4.其他的进程替换函数
1.int execv(const char *path, char *const argv[])
我们通过命令行参数表的形式获取执行该程序要怎么做
#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/wait.h> int main() { printf("test begin\n"); int id=fork(); if(id==0) { sleep(2); char *const argv[]= { (char*) "ls", (char*) "-l", (char*) "-a", (char*) "--color", NULL }; execv("/usr/bin/ls",argv); exit(1); } int status=0; int reid=waitpid(id,&status,0); if(reid>0) { printf("father wait success,child exit code:%d\n",WEXITSTATUS(status)); } printf("test end\n"); return 0; }
命令行参数指针数组中要存对应指令以及选项的字符串地址,强转为char*,字符串的首地址
2.int execvp(const char *file, char *const argv[])
第一个参数直接写程序名称,p:代表路径会自动在环境变量PATH里面找
倒数第二个v:vector,用数组来记录程序怎么执行
#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/wait.h> int main() { printf("test begin\n"); int id=fork(); if(id==0) { sleep(2); char *const argv[]= { (char*) "ls", (char*) "-l", (char*) "-a", (char*) "--color", NULL }; execvp("ls",argv); exit(1); } int status=0; int reid=waitpid(id,&status,0); if(reid>0) { printf("father wait success,child exit code:%d\n",WEXITSTATUS(status)); } printf("test end\n"); return 0; }
3.int execlp(const char *file, const char *arg, ...)
p:路径可以在PATH环境变量里面找
#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/wait.h> int main() { printf("test begin\n"); int id=fork(); if(id==0) { sleep(2); execlp("ls","ls","-a","-l",NULL); exit(1); } int status=0; int reid=waitpid(id,&status,0); if(reid>0) { printf("father wait success,child exit code:%d\n",WEXITSTATUS(status)); } printf("test end\n"); return 0; }
4.int execvpe(const char *file, char *const argv[],char *const envp[]);
`最后的e:表示环境变量
替换子进程的cpp
#include<iostream> #include<unistd.h> #include <sys/types.h> using namespace std; int main(int argc,char*argv[],char*envp[]) { for(int i=0;i<argc;i++) {cout<<argv[i]<<endl;} for(int i=0;envp[i];i++) { cout<<envp[i]<<endl; } }
#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/wait.h> int main() { printf("test begin\n"); int id=fork(); if(id==0) { sleep(2); char *const argv[]= { (char*) "./", (char*) "exe1", NULL }; char *const engv[]= { (char*) "HELLO=1111111111", (char*) "ERZI=22222222222", (char*) "SOUZI=33333333333", (char*) "GUIZI=44444444444", NULL }; execvpe("exe1",argv,engv); exit(1); } int status=0; int reid=waitpid(id,&status,0); if(reid>0) { printf("father wait success,child exit code:%d\n",WEXITSTATUS(status)); } printf("test end\n"); return 0; }
该cpp程序父进程是c程序,爷爷进程是bash,要获取爷爷的环境变量用上面的方法修改
总结第四个函数:
1.用全新的环境变量给子进程
2.用爷爷进程的环境变量给孙子进程,environ
3.老的环境变量加一些,putenv
而对应putenv,我们可以查一下手册
man putenv • 1