网站开发毕业设计说明,孝感网站建设,记录开发wordpress主题,repress wordpress文章目录 一、看一看单进程版的进程替换二、进程替换的原理三、多进程版——验证各种程序替换接口exec系列函数execlexeclpexecvexecvp tipsexecleexecve 四、总结 一、看一看单进程版的进程替换
#includestdio.h
#includeunistd.h
#includestdlib.hi… 文章目录 一、看一看单进程版的进程替换二、进程替换的原理三、多进程版——验证各种程序替换接口exec系列函数execlexeclpexecvexecvp tipsexecleexecve 四、总结 一、看一看单进程版的进程替换
#includestdio.h
#includeunistd.h
#includestdlib.hint main()
{printf(before : I am a process, pid : %d,ppid : %d\n,getpid(),getppid());execl(/usr/bin/ls, ls , -a , -l, NULL);printf(after : I am a process, pid : %d,ppid : %d\n,getpid(),getppid());return 0;
}通过代码和现象可以看出执行了execl函数之后其之后的代码不再被执行。 而是执行了 ls -a -l 这条指令。 二、进程替换的原理 CPU首先执行父进程的代码打印出before语句后接下来执行execl系统调用。
ls -a -l也是一个文件放在磁盘中execl将ls -a -l文件的代码和数据进行替换把调用execl系统调用的进程的数据和代码替换掉
替换后execl之后的代码不再被执行。
注意进程替换仅仅是替换掉进程的数据和代码并没有创建新的进程。所以进程的id没有改变
补充说明
1.程序替换成功后exec 系列的函数后面的代码不会被执行。2.如果程序替换失败才有可能执行后续的代码并且替换成功没有返回值替换失败才有返回值。 三、多进程版——验证各种程序替换接口
exec系列函数 execl
int execl(const char *path, const char *arg, ...);exec系列是进程替换的系统调用系列函数l代表的就是list的意思。
就是链式的。
具体使用方法
execl(/usr/bin/ls, ls , -a , -l, NULL);第一个参数就是执行的命令文件所在的路径。 第二个参数往后开始就是要执行什么命令 平常执行的命令是这样的ls -a -l 现在传参给execl后只需要把空格变成逗号即可并在最后加上一个NULL即可 execl第一个参数要传路径的原因 想要执行一个程序就必须先找到这个程序
execlp
int execlp(const char *file, const char *arg, ...);p代表的就是PAHT环境变量。 代表的就是从自己的环境变量中查找路径。
所以标准写法如下
execlp(ls, ls , -a , -l, NULL);这样写不带路径执行该函数时系统会去环境变量中查找该命令所在路径。
当然也可以这样写
execlp(/usr/bin/ls, ls , -a , -l, NULL);这样写对编译器更好也不用编译器自己去找了。
这里有个问题
execlp(ls, ls , -a , -l, NULL);第一个ls和第二个ls一样吗
答案是不一样的前面说过要执行一个程序必须先找到该程序。 第一个ls其实就是程序所在的路径只不过该函数可以通过PATH环境变量帮助我们找到ls这个命令。 也就是说通过环境变量和第一个ls就能找到ls所在的路径/usr/bin/ls
而第二个ls是我该怎么执行ls这个命令。
总结第一个ls是找到ls这个命令在哪第二个ls表示的是该怎么执行ls这个命令。
execv
这里的v就代表vector也就是顺序表。
int execv(const char *path, char *const argv[]);传递的第二个参数就由list变成了字符串指针数组。 核心的传参方式如下
char* const argv[] {ls,-a,-l,NULL};
execv(/usr/bin/ls,argv);第一个参数是路径表示操作系统需要去哪个路径下执行命令第二个参数是字符串指针数组。经过操作系统层面会将数组的每一个字符串提取出来传递给第一个参数。
因为一个可执行程序肯定也有main函数也就是说将argv作为参数传给了main函数main函数就知道怎么执行该命令了。
execvp
与execlp类似
int execvp(const char *file, char *const argv[]);第一个参数传递的是文件路径但是由于有环境变量的存在使得CPU执行该系统调用时不费什么劲就能找到file文件。
char* const argv[] {ls,-a,-l,NULL};
execvp(ls,argv);第一个ls表明所需要执行的指令所在路径。
tips 注意execl函数不仅能调用系统提供的函数还能调用用户自己的命令也就是还能通过execl函数调用其他可执行程序。 execl(./otherExe,otherExe,NULL);因为不管是什么语言都能夸语言调用 因为无论是可执行程序还是脚本本质都是进程
是进程都能进行进程进程替换都能用exec系列函数调用
所以可以通过该调用方法来调用可执行程序。
验证execv可以将命令传递给其他可执行程序。
otherExe.c文件
int main(int argc,const char* argv[])
{int i 0;for(;iargc;i){printf(%s\n,argv[i]);}return 0;
}test.c
int main()
{//多进程版进程替换char* const argv[] {ls,-a,-l,NULL};pid_t id fork();if(id 0){//childprintf(before : I am a child process, pid : %d,ppid : %d\n,getpid(),getppid());execvp(./otherExe,argv);printf(after : I am a child process, pid : %d,ppid : %d\n,getpid(),getppid());exit(0);}//father sleep(3);int status;pid_t ret waitpid(id,status,WNOHANG);if(ret id){printf(wait success! wait pid is : %d \n,id);} return 0;
}执行test可执行程序后会将argv参数传递给otherExe可执行程序然后打印出来。
总结通过exec系列函数可以调用其他的可执行程序。 问题2进程替换时环境变量会被替换吗?
答案是并不会。
当我们在test.c中调用otherExe.c时并没有将环境变量传递给otherExe函数。 但是通过进程替换仍然可以看到otherExe函数仍然可以打印出环境变量 otherExe.c文件如下printf(这是命令行参数\n);
int i 0;
for(;argv[i];i)
{printf(%s\n,argv[i]);
}
printf(这是环境变量信息\n);i 0;
for(;env[i];i)
{printf(%s\n,env[i]);
}结论环境变量不会被进程替换给替换掉进程替换只是替换进程的代码和数据。 环境变量会随着继承关系从父进程继承下来。 环境变量也是数据创建子进程的时候就已经继承下来了。 在bash进程中导入环境变量
export xxxxxx;bash中导入环境变量同样会被子进程继承下来。
如果不想从bash中导入而是从某一个进程中导入环境变量则使用一个系统调用putenv
int putenv(char *string);哪个进程调用该函数就向哪个进程中导入环境变量。
此后所有该父进程的子进程都会继承该环境变量下来。
所以从bash开始只要导了环境变量越往下环境变量会越来越多。 execle
int execle(const char *path, const char *arg,..., char * const envp[]);最后一个参数是环境变量数组也就是当前进程的环境变量表。 在库的声明中有一个environ变量使用该变量也能将环境变量传给execle函数。
通过调用其他可执行程序就能打印出环境变量了。
execve
int execve(const char *path, char *const argv[], char *const envp[]);同样只是比execv多了一个参数该参数可以传environ也就是把当前进程的环境变量传过去即可。 实际上execve才是真正的系统调用其他的exec*函数最终都是调用execve所以execve在man手册的第二节也就是系统调用那节其他函数在man手册第三节。 四、总结
这篇文章重点讲解exec系列函数。