vfork用于创建一个新进程,而该新进程的目的是exec一个新进程,
vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间
完全复制到子进程中,因为子进程会立即调用exec,于是也就不会存放该地址空间。不过在子进程中调用exec或exit之前,他在父进程的空间中运行。
vfork和fork之间的另一个区别是: vfork保证子进程先运行,在她调用exec或exit之后
父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作
,则会导致死锁。
用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序,
当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数
开始执行,因为调用exec并不创建新进程,所以前后的进程id 并未改变,exec只是用
另一个新程序替换了当前进程的正文,数据,堆和栈段。
例子1:用fork创建子进程
#include "apue.h"
int glob = 6; /* external variable in initialized data */
int
main(void)
{
int var; /* automatic variable on the stack */
pid_t pid;
var = 88;
printf("before vfork\n"); /* we don't flush stdio */
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) { /* child */
glob++; /* modify parent's variables */
var++;
_exit(0); /* child terminates */
}
/*
* Parent continues here.
*/
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
}
输出:
a write to stdout
before fork
pid = 3130,glob = 6,var = 88
pid = 3131,glob = 7,var = 89
这里printf一次,但却输出两次,为什么?
用fork创建的子进程会产生父进程的副本,即子进程会copy调用fork函数后的代码断,本例子中子进程拥有:
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
同样父进程也拥有:
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
当每一个进程终止时,其缓存中的内容被输出。
例子2:用vfork创建子进程
#include "apue.h"
int glob = 6; /* external variable in initialized data */
int
main(void)
{
int var; /* automatic variable on the stack */
pid_t pid;
var = 88;
printf("before vfork\n"); /* we don't flush stdio */
if ((pid = vfork()) < 0) {
err_sys("vfork error");
} else if (pid == 0) { /* child */
glob++; /* modify parent's variables */
var++;
_exit(0); /* child terminates */
}
/*
* Parent continues here.
*/
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
}
输出:
a write to stdout
before fork
pid = 3169,glob = 7,var = 89