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