关键字:子进程,exec,环境变量
使用fork或vfork创建子进程后,子进程通常会调用exec函数来执行另外一个程序。系统调用exec用于执行一个可执行程序以
替代当前进程的执行映像。
注意:exec调用并没有创建新的进程。一个进程一旦调用exec函数,它本身就“死亡”了,系统把代码段替换成新的程序的代码,
废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一保留的就是进程ID。也就是说,对系统而言,还是
同一个进程,不过执行的已经是另外一个程序了。
exec函数:
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
--------------------------------------------------------------------------------
环境变量:用户的主目录,终端类型,当前目录等,它们定义了用户的工作环境,所以称为环境变量。
可以使用指令env查看系统环境变量。
用户也可以修改这个变量的值,以制定自己的工作环境。
代码中通过系统预定义的全局变量environ显示各个环境变量的值。
事实上main函数的完整形式应该是:
int main(int argc, char* argv[], char** envp);
参数envp就是系统环境变量。
测试代码:
#include <stdio.h> #include <unistd.h> extern char** environ; int main(int argc, char** argv, char** envp) { char** p = environ; char** q = envp; while(*p != NULL) { printf("%s\n", *p++); printf("%s\n", *q++); printf("----------\n"); } return 0; }
-----------------------------------------------------------------------------------------------
exec函数与环境变量的关系:
无论是哪个exec函数,都是可以将可执行程序的路径、命令行参数和环境变量3个参数传递给可执行程序的main函数。
程序一:p.c
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main(int argc, char* argv[], char **envp) { int i = 0; printf("after execve, my pid is:%d\n", getpid()); for(i=0;i<argc;i++) { printf("argv[%d]=%s\n", i, argv[i]); } return 0; }
程序二:ex.c
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char* argv[], char* envp[]) { pid_t pid = 0; int stat; printf("test execve\n"); pid = fork(); if (pid < 0) { exit(0); } else if (pid == 0) { printf("the child's pid is:%d\n", getpid()); execve("p", argv, envp); printf("go on run\n"); } printf("parent is running\n"); wait(&stat); printf("quit\n"); return 0; }
将第一个程序编译:
gcc -o p p.c
编译第二个程序:
gcc -o ex ex.c
执行ex程序:
test execve
parent is running
the child's pid is:26152
after execve, my pid is:26152
argv[0]=./ex
argv[1]=ll
quit
从执行结果来看,execve调用的程序,保持了原来的进程ID,父进程ID。
同时,我们还可以看到当调用新的可执行程序后,原有的子进程的映像被替代,不在被执行。
子进程不会去执行printf("go on run\n");因为子进程已经被新的执行映像替代。
执行新程序后的进程保持了原来进程的许多特征,如:
1、文件锁
2、控制终端
3、当前工作目录
4、根目录
5、创建文件时使用的屏蔽字
6、进程信号屏蔽字
7、未决警告
8、和进程相关的使用处理器的时间
9、实际用户ID
10、实际组ID