fork和vfork的区别

fork()和vfork()都是创建一个进程,区别在于:

fork():子进程拷贝父进程的数据段和代码段,且父子进程的执行顺序是不确定的

vfork():共享父进程的数据段,确保子进程优先执行,在调用exec或exit之前与父进程共享数据段,在调用exec或exit父进程才可能被调度运行。如果在调用这两个函数之前,子进程依赖于父进程的进一步动作,则会造成死锁。

举例如下:

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

void main()

{

      pid_t pid;

      pid = fork();

      if(pid < 0)

     {

           printf("process create error!/n");

      }

      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());

     }

}

#gcc fork1.c -o fork1

# ./fork1   

I am the parent process,ID is 4237

I am the child process,ID is 4238

因为fork()用于从一个已存在的进程中,创建一个新的进程。新的进程为子进程,原来的进程为父进程。fork()的返回值有两个,子进程返回0,父进程返回子进程的进程号,进程号都是非零的整数。在调用pid=fork()之前,只有父进程在运行,而在pid=fork()之后,父子进程都在运行。pid==0则是子进程,pid!=0则是父进程。我们知道fork()在创建进程时,会拷贝父进程的数据段和代码段,所以子进程中也包含了一下代码:

   if(pid < 0){

       printf("process create error!/n");

   }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());

   }

以上代码在父子进程中个执行一次,所以打印两条语句。

例子:

void main()

{

   int count = 0;

   pid_t pid;

   pid = fork();

   count++;

   printf("count is %d/n",count);

   return 0;

}

# gcc fork2.c -o fork2

# ./fork2

count= 1

count= 1

这里count为什么不是2呢?再强调一次,fork()函数中的子进程拷贝父进程的数据段和代码段。所以

   count++;

   printf("count is %d/n",count);

在父子进程中各执行一次,但子进程使用的是自己的数据段(这和从父进程中拷贝过来的一模一样)。它们互不影响。

接下来分析vfork()

将上述程序的fork()换成vfork(),结果如下:

count is 1

count is -1210017386

段错误

本来vfock()是共享数据段的,结果应该是 2,为什么不是预想的 2 呢?

知识点:vfrok与fork的一个区别就是vfork保证子进程优先执行,在他调用exec或则exit之后,父进程才可能被调度执行。如果调用者两个函数之前,子进程依赖于父进程的进一步动作则会死锁。将程序做如下修改:
int main()
{
  pid_t pid;
  int count =0;
  pid = vfork();
 
  if(pid == 0){
     count ++;
     _exit(0);
  }else{
     count++
     printf("the count is %d/n",count);
  }
 
  return 0;
}
结果:

count is 2

如果没有_exit(0)的话,子进程没有调用 exec或 exit,所以父进程是不可能执行的,在子进程调用exec或exit 之后父进程才可能被调度运行。 所以我们加上_exit(0);使得子进程退出,父进程执行,这样 else后的语句就会被父进程执行,又因在子进程调用exec或exit之前与父进程数据是共享的,所以子进程退出后把父进程的数据段count改成1了,子进程退出后,父进程又执行,最终就将count 变成了2

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

pid:  current->pid

cpu: smp_processor_id()

command: current->comm

转自:http://blog.csdn.net/lijierson8/archive/2010/10/11/5932764.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值