fork()与vfork()都是创建一个进程,那他们有什么区别呢?总结有以下三点区别:
1. fork ():子进程拷贝父进程的数据段,代码段
vfork ( ):子进程与父进程共享数据段
2. fork ()父子进程的执行次序不确定
vfork 保证子进程先运行,在调用exec 或exit 之前与父进程数据是共享的,在它调用exec
或exit 之后父进程才可能被调度运行。
3. vfork ()保证子进程先运行,在她调用exec 或exit 之后父进程才可能被调度运行。如果在
调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
上一节主要说明fork函数的用法,这节主要用vfork函数举例子,以便两者比较查看。了下面通过几个例子加以说明:
例子1:
#include
#include
int main ()
{
pid_t fpid; //fpid表示fork函数返回的值
char *pstr = NULL;
int count=0;
fpid=vfork(); if (fpid < 0) printf("error in fork!\n"); else if (fpid == 0) { printf("i am the child process, my process id is %d\n",getpid()); printf("child\n"); count++; } else { printf("i am the parent process, my process id is %d\n",getpid()); printf("parent\n"); count++; } printf("%s, %d, %d\n", __FUNCTION__, __LINE__,count); return 0;
输出结果:
自己试一下狂打印之后才停止,而且日志都是乱的。
本来vfork()是共享数据段的,结果应该是2,为什么不是预想的2 呢?先看一个知识点:
vfork 和fork 之间的另一个区别是:vfork 保证子进程先运行,在她调用exec 或exit 之
后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动
作,则会导致死锁。
这样上面程序中的fork ()改成vfork()后,vfork ()创建子进程并没有调用exec 或exit,
所以最终将导致死锁。
怎么改呢?看下面程序:
#include
#include
int main ()
{
pid_t fpid; //fpid表示fork函数返回的值
char *pstr = NULL;
int count=0;
fpid=vfork();
if (fpid < 0)
printf("error in fork!\n");
else if (fpid == 0) {
printf("i am the child process, my process id is %d\n",getpid());
printf("child\n");
count++;
_exit(0);
}
else {
printf("i am the parent process, my process id is %d\n",getpid());
printf("parent\n");
count++;
}
printf("%s, %d, %d\n", __FUNCTION__, __LINE__,count);
return 0;
}
输入结果为:
i am the child process, my process id is 17054
child
i am the parent process, my process id is 17053
parent
main, 99, 2
此结果中可以看到输出的count为2。所以可以看出vfork使用的时候要注意子进程要exit后父进程方可执行,而且栈中的count是父子共享的。跟fork是不同的。
如果没有_exit(0)的话,子进程没有调用exec 或exit,所以父进程是不可能执行的,在子进程调用exec 或exit 之后父进程才可能被调度运行。
所以我们加上_exit(0);使得子进程退出,父进程执行,这样else 后的语句就会被父进程执行,又因在子进程调用exec 或exit之前与父进程数据是共享的,所以子进程退出后把父进程的数据段count改成1 了,子进程退出后,父进程又执行,最终就将count变成了2,看下实际 运行结果:
网上抄的一段,可以再理解理解:
为什么会有vfork,因为以前的fork 很傻, 它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行exec 调用,这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子 霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec 或者exit 后,相儿子买了自己的房子了,这时候就相于分家了。