Chinaunix首页 | 论坛 | 博客
  • 博客访问: 312813
  • 博文数量: 172
  • 博客积分: 25
  • 博客等级: 民兵
  • 技术积分: 895
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-09 16:57
文章分类

全部博文(172)

文章存档

2012年(86)

2011年(86)

分类:

2011-11-10 09:58:52

原文地址:fork()与vfork()的区别 作者:pursuitxh

fork()与vfock()都是创建一个进程,那他们有什么区别呢?总结有以下三点区别:

1.       fork():子进程拷贝父进程的数据段,代码段

vfork():子进程与父进程共享数据段

2.       fork()父子进程的执行次序不确定

vfork保证子进程先运行,在调用execexit之前与父进程数据是共享的,在它调用execexit之后父进程才可能被调度运行。

3.  vfork保证子进程先运行,在她调用execexit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

下面通过几个例子加以说明:

第一:子进程拷贝父进程的代码段的例子:

#include

#include

#include

int main()

{

       pid_t pid;

       pid=fork();

       if(pid<0)

              printf("error in fork!");

       else if(pid==0)

              printf("I am the child process,ID is %d\n",getpid());

       else

              printf("I am the parent process,ID is %d\n",getpid());

}

运行结果:

[root@lwm liweimeng]# gcc fork1.c -o fork1

[root@lwm liweimeng]# ./fork1

I am the child process,ID is 4238

I am the parent process,ID is 4237

为什么两条语句都会打印呢?这是因为fork()函数用于从已存在的进程中创建一个新的进程,新的进程称为子进程,而原进程称为父进程,fork()的返回值有两个,子进程返回0,父进程返回子进程的进程号,进程号都是非零的正整数,所以父进程返回的值一定大于零,在pid=fork();语句之前只有父进程在运行,而在pid=fork();之后,父进程和新创建的子进程都在运行,所以如果pid==0,那么肯定是子进程,若pid=0(事实上肯定大于0),那么是父进程在运行。而我们知道fork()函数子进程是拷贝父进程的代码段的,所以子进程中同样有

if(pid<0)

              printf("error in fork!");

       else if(pid==0)

              printf("I am the child process,ID is %d\n",getpid());

       else

              printf("I am the parent process,ID is %d\n",getpid());

}

这么一段代码,所以上面这段代码会被父进程和子进程各执行一次,最终由于子进程的pid= =0,而打印出第一句话,父进程的pid>0,而打印出第二句话。于是得到了上面的运行结果。

再来看一个拷贝数据段的例子:

#include

#include

int main(void)

{

       pid_t pid;

       int count=0;

 

       pid=fork();

 

       count++;

       printf("count= %d\n",count);

 

       return 0;

}    

大家觉着打印出的值应该是多少呢?是不是2呢?先来看下运行结果吧

[root@lwm liweimeng]# gcc fork2.c  -o fork2

[root@lwm liweimeng]# ./fork2

count= 1

count= 1

为什么不是2呢?因为我们一次强调fork()函数子进程拷贝父进程的数据段代码段,所以count++;

       printf("count= %d\n",count);

 

       return 0

将被父子进程各执行一次,但是子进程执行时使自己的数据段里面的(这个数据段是从父进程那copy过来的一模一样)count+1,同样父进程执行时使自己的数据段里面的count+1,他们互不影响,与是便出现了如上的结果。

那么再来看看vfork()吧。如果将上面程序中的fork()改成vfork(),运行结果是什么样子的呢?

[root@lwm liweimeng]# gcc fork2.c -o fork2

[root@lwm liweimeng]# ./fork2

count= 1

count= 1

总线错误

本来vfock()是共享数据段的,结果应该是2,为什么不是预想的2呢?先看一个知识点:

vforkfork之间的另一个区别是: vfork保证子进程先运行,在她调用execexit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

这样上面程序中的fork()改成vfork()后,vfork()创建子进程并没有调用execexit,所以最终将导致死锁。

怎么改呢?看下面程序:

#include

#include

#include

int main(void)

{

       pid_t pid;

       int count=0;

 

       pid=vfork();

 

       if(pid==0)

       {

              count++;

              _exit(0);

       }

       else

       {

              count++;

       }

       printf("count= %d\n",count);

 

       return 0;

}    

如果没有_exit0)的话,子进程没有调用execexit,所以父进程是不可能执行的,在子进程调用execexit之后父进程才可能被调度运行。

所以我们加上_exit(0);使得子进程退出,父进程执行,这样else后的语句就会被父进程执行,又因在子进程调用execexit之前与父进程数据是共享的,所以子进程退出后把父进程的数据段count改成1了,子进程退出后,父进程又执行,最终就将count变成了2,看下实际运行结果:

[root@lwm liweimeng]# gcc fork2.c -o fork2

[root@lwm liweimeng]# ./fork2

count= 2

 

网上抄的一段,可以再理解理解:

为什么会有vfork,因为以前的fork很傻,当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行exec调用,这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“ 霸占着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec或者exit后,相当于儿子买了自己的房子了,这时候就相当于分家了。

阅读(487) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~