创建子进程后,我们并不希望子进程执行父进程后续相同的内容,这时我们可以用exec函数族进行子进程的执行内容替换。
exec函数族Linux下的exec函数族,是指6个以exec开头的函数。分别是
int execl(const char *path,const char *arg,...) int execv(const char *path,char *cosnt arg[]) int execle(const char *path,const char *arg,...,char *const envp[]) int execve(const char *path,char *const argv[],char *const envp[]) int execlp(const char *file, const char *arg,...) int execvp(const char *file, char *const argv[]);
复习:牢记const修饰的是谁?指针标记的优先级低于偏移符号[]。
const char *p:p是一个指针,指向常字符类型
char const *p:同上,const修饰的是*p
char * const p:p是一个常指针,指向字符类型。const修饰的是p
char *p[]:p是一个数组,其内容是字符指针
char (*p)[]:p是一个指针,指向的内容是字符数组(字符串)
char * const p[]:p是一个数组,数组的内容是常字符指针
我们介绍最常用的第一个程序:
int execl(const char *path,const char *arg,...)执行原理
为什么说exec函数族可以使子进程执行不同的程序呢?
——“换核不换壳”:进程在调用exec函数时,进程用户空间的代码和数据空间的代码会完全被新的替代。也就是说原有的text和data会被替换掉,但是调用exec函数并不会产生新的进程,也不会改变PID。
直白地讲,就是原有的箱子不变。但是调用exec函数后,其中原有的苹果被换成了梨。
- 进程认为自己不能再为系统和用户作出任何贡献时,就可以调用任何exec函数族让自己重生
- 如果一个进程想要执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用任何一个exec函数使子进程重生。
我们依旧举一些例子:
//main.c文件 #include#include #include int main(void) { //int execl(const char *pathname, const char *arg, ... // ); //第一个参数是要执行的执行文件的路径(包含文件名),第二个是要执行文件的文件名 //之后的变长参数就是要带的参数。最后要以(char *)NULL作为最后一个参数 pid_t pid; pid=fork(); if(pid<0) { printf("process create failed!"); } else if(pid == 0) { printf("This is child process!"); printf("PID=%d parent PID=%dn",getpid(),getppid()); execl("/home/czc/Desktop/LinuxExp/process/subproc","subproc",(char *)NULL); exit(1); } else { printf("This is parent process!"); printf("PID=%d Its child PID=%dn",getpid(),pid); } printf("This is father process remaining part!n"); return 0; }
//./subproc.c文件 #includeint main(void) { printf("enter a new subProcess!n"); return 0; }
调用main.c编译的可执行文件结果如下:
可以发现,父进程剩下的部分,子进程并没有执行。子进程在调用exec函数族后,就只执行subproc.c编译出来的可执行文件了。这里使用exit(1)的目的只是在exec调用失败后,也主动结束子进程。
之前已经提到,Linux下的命令就是可执行文件。那么同样地,我们在调用exec函数族时不仅可以使用我们自己编写的可执行文件,也可以调用系统命令(也就是系统自带的可执行文件)。我们对上面的C源文件稍作修改:
//main.c文件 #include#include #include int main(void) { //int execl(const char *pathname, const char *arg, ... // ); //第一个参数是要执行的执行文件的路径(包含文件名),第二个是要执行文件的文件名 //之后的变长参数就是要带的参数。最后要以(char *)NULL作为最后一个参数 pid_t pid; pid=fork(); if(pid<0) { printf("process create failed!"); } else if(pid == 0) { printf("This is child process!"); printf("PID=%d parent PID=%dn",getpid(),getppid()); //ls命令在路径/bin/下 execl("/bin/ls","ls","-al",(char *)NULL); exit(1); } else { printf("This is parent process!"); printf("PID=%d Its child PID=%dn",getpid(),pid); } printf("This is father process remaining part!n"); return 0; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)