fork和vfork的区别

    技术2026-01-13  0

    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)