vfork导致父进程环境变量被修改
vfork版本
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
static int childProcess(void *arg) {
char* env = getenv("MY_ENV");
printf("childProcess %d env:%s\n", getpid(), env);
setenv("MY_ENV", "helloword", 1);
exit(0);
}
int main(void) {
volatile pid_t resultPid = vfork();
if (resultPid == 0) {
childProcess(NULL);
}
volatile pid_t resultPid1 = vfork();
if (resultPid1 == 0) {
childProcess(NULL);
}
char* env = getenv("MY_ENV");
printf("main process %d env:%s\n", getpid(), env);
assert(resultPid != 0); /* childProcess never returns */
assert(resultPid1 != 0); /* childProcess never returns */
return 0;
}
运行结果
childProcess 12451 env:(null)
childProcess 12452 env:helloword
main process 12450 env:helloword
可以看出,父进程没有设置环境变量MY_ENV,但是由于子进程12451 设置了环境变量,导致主进程12450 也被设置了。
fork版本
// vfork.c
static int childProcess(void *arg) {
char* env = getenv("MY_ENV");
printf("childProcess %d env:%s\n", getpid(), env);
setenv("MY_ENV", "helloword", 1);
exit(0);
}
int main(void) {
// volatile pid_t resultPid = vfork();
volatile pid_t resultPid = fork();
if (resultPid == 0) {
childProcess(NULL);
}
// volatile pid_t resultPid1 = vfork();
volatile pid_t resultPid1 = fork();
if (resultPid1 == 0) {
childProcess(NULL);
}
char* env = getenv("MY_ENV");
printf("main process %d env:%s\n", getpid(), env);
assert(resultPid != 0); /* childProcess never returns */
assert(resultPid1 != 0); /* childProcess never returns */
return 0;
}
运行结果
main process 14304 env:(null)
childProcess 14305 env:(null)
childProcess 14306 env:(null)
可以看出,即使子进程设置了环境变量,但是并没有影响其他子进程。
vfork + execve版本
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
static int childProcess(void *arg) {
char *argVec[10]; //参数数组
char *envVec[] = {"环境参数1","环境参数2",NULL}; //环境变量数组
printf("childProcess %d exec\n", getpid());
execve("./exec", argVec,envVec);
}
static int childProcess1(void *arg) {
char* env = getenv("MY_ENV");
printf("childProcess %d env:%s\n", getpid(), env);
// setenv("MY_ENV", "helloword", 1);
exit(0);
}
int main(void) {
volatile pid_t resultPid = vfork();
// volatile pid_t resultPid = fork();
if (resultPid == 0) {
childProcess(NULL);
}
sleep(1);
volatile pid_t resultPid1 = vfork();
// volatile pid_t resultPid1 = fork();
if (resultPid1 == 0) {
childProcess1(NULL);
}
char* env = getenv("MY_ENV");
printf("main process %d env:%s\n", getpid(), env);
assert(resultPid != 0); /* childProcess never returns */
assert(resultPid1 != 0); /* childProcess never returns */
return 0;
}
// exec.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
char* env = getenv("MY_ENV");
printf("childProcess %d env :%s\n", getpid(), env);
setenv("MY_ENV", "helloword", 1);
// char* env1 = getenv("MY_ENV");
// printf("childProcess %d env1:%s\n", getpid(), env1);
return 0;
}
运行结果
childProcess 16605 exec
childProcess 16605 env :(null)
childProcess 16606 env:(null)
main process 16604 env:(null)
子进程在执行完execve后,修改环境变量对主进程已经没有影响。
结论:
- fork创建一个进程时,子进程只是完全复制父进程的资源,子进程的修改并不会影响父进程
- vfork系统调用不同于fork,用vfork创建的子进程与父进程共享地址空间,也就是说子进程完全运行在父进程的地址空间上,如果这时子进程修改了某个变量,这将影响到父进程。
- 一个进程一旦调用exec类函数,它本身就“死亡”了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,exec类函数中有的还允许继承环境变量之类的信息,这个通过exec系列函数中的一部分函数的参数可以得到。
- vfork会保证子进程先运行