人间乐土吧 关注:14贴子:334
  • 4回复贴,共1

【IT】FORK()函数的理解

只看楼主收藏回复

  对于刚刚接触Unix/Linux操作系统,在Linux下编写多进程的人来说,fork是最难理解的概念之一:它执行一次却返回两个值。
  首先我们来看下fork函数的原型:
  #include <sys/types.h>
  #include <unistd.h>
  pid_t fork(void);
  返回值:
  负数:如果出错,则fork()返回-1,此时没有创建新的进程。最初的进程仍然运行。
  零:在子进程中,fork()返回0
  正数:在负进程中,fork()返回正的子进程的PID
  其次我们来看下如何利用fork创建子进程。
  创建子进程的样板代码如下所示:
  pid_t child;
  if((child = fork())<0)
  /*错误处理*/
  else if(child == 0)
  /*这是新进程*/
  else
  /*这是最初的父进程*/
  fock函数调用一次却返回两次;向父进程返回子进程的ID,向子进程中返回0,
  这是因为父进程可能存在很多过子进程,所以必须通过这个返回的子进程ID来跟踪子进程,
  而子进程只有一个父进程,他的ID可以通过getppid取得。
  下面我们来对比一下两个例子:
  第一个:
  #include <unistd.h>
  #include <stdio.h>
  int main()
  {
  pid_t pid;
  int count=0;
  pid = fork();
  printf( "This is first time, pid = %d\n", pid );
  printf( "This is secONd time, pid = %d\n", pid );
  count++;
  printf( "count = %d\n", count );
  if ( pid>0 )
  {
  printf( "This is the parent process,the child has the pid:%d\n", pid );
  }
  else if ( !pid )
  {
  printf( "This is the child Process.\n")



1楼2012-11-13 17:09回复
      }
      else
      {
      printf( "fork failed.\n" );
      }
      printf( "This is third time, pid = %d\n", pid );
      printf( "This is fouth time, pid = %d\n", pid );
      return 0;
      }
      运行结果如下:



      问题:
      这个结果很奇怪了,为什么printf的语句执行两次,而那句“count++;”的语句却只执行了一次
      接着看:
      #include <unistd.h>
      #include <stdio.h>
      int main(void)
      {
      pid_t pid;
      int count=0;
      pid = fork();
      printf( "Now, the pid returned by calling fork() is %d\n", pid );
      if ( pid>0 )
      {
      printf( "This is the parent procESS,the child has the pid:%d\n", pid );
      printf( "In the parent process,count = %d\n", count );
      }
      else if ( !pid )
      {
      printf( "This is the child process.\n");
      printf( "Do your own things here.\n" );
      count ++;
      printf( "In the child process, count = %d\n", count );
      }
      else
      {
      printf( "fork failed.\n" );
      }
      return 0;
      }
      运行结果如下:
      现在来解释上面提出的问题。
      看这个程序的时候,头脑中必须首先了解一个概念:在语句pid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同,将要执行的下一条语句都是if ( pid>0 )……。
    


    2楼2012-11-13 17:09
    回复
        我们来给出详细的注释
        #include <unistd.h>
        #include <stdio.h>
        int main(void)
        {
        pid_t pid;
        int count=0;
        /*此处,执行fork调用,创建了一个新的进程, 这个进程共享父进程的数据和堆栈空间等,这之后的代码指令为子进程创建了一个拷贝。 fock 调用是一个复制进程,fock 不象线程需提供一个函数做为入口, fock调用后,新进程的入口就在 fock的下一条语句。*/
        pid = fork();
        /*此处的pid的值,可以说明fork调用后,目前执行的是父进程还是子进程*/
        printf( "Now, the pid returned by calling fork() is %d\n", pid );
        if ( pid>0 )
        {
        /*当fork在子进程中返回后,fork调用又向父进程中返回子进程的pid, 如是该段代码被执行,但是注意的事,count仍然为0, 因为父进程中的count始终没有被重新赋值, 这里就可以看出子进程的数据和堆栈空间和父进程是独立的,而不是共享数据*/
        printf( "This is the parent process,the child has the pid:%d\n", pid );
        printf( "In the parent process,count = %d\n", count );
        }
        else if ( !pid )
        { /*在子进程中对count进行自加1的操作,但是并没有影响到父进程中的count值,父进程中的count值仍然为0*/
        printf( "This is the child process.\n");
        printf( "Do your own things here.\n" );
        count++;
        printf( "In the child process, count = %d\n", count );
        }
        else
        {
        printf( "fork failed.\n" );
        }
        return 0;
        }
        也就是说,在Linux下一个进程在内存里有三部分的数据,就是"代码段"、"堆栈段"和"数据段"。"代码段",顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段。"堆栈段"存放的就是子程序的返回地址、子程序的参数以及程序的局部变量。而数据段则存放程序的全局变量,常数以及动态数据分配的数据空间(比如用malloc之类的函数取得的空间)。系统如果同时运行数个相同的程序,它们之间就不能使用同一个堆栈段和数据段。
        仔细分析后,我们就可以知道:
        一个程序一旦调用fork函数,系统就为一个新的进程准备了前述三个段,首先,系统让新的进程与旧的进程使用同一个代码段,因为它们的程序还是相同的,对于数据段和堆栈段,系统则复制一份给新的进程,这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。
        fork()不仅创建出与父进程代码相同的子进程,而且父进程在fork执行点的所有上下文场景也被自动复制到子进程中,包括:
        ——全局和局部变量
        ——打开的文件句柄
        ——共享内存、消息等同步对象
        而如果两个进程要共享什么数据的话,就要使用另一套函数(shmget,shmat,shmdt等)来操作。现在,已经是两个进程了,对于父进程,fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零,这样,对于程序,只要判断fork函数的返回值,就知道自己是处于父进程还是子进程中。
        “本文由华清远见http://www.embedu.org/index.htm提供”
      


      4楼2012-11-13 17:09
      回复
        最简单的fork炸弹程序
        #include <unistd.h>
        int main()
        {
        while(1)
        fork();
        return 0;
        }


        5楼2012-11-13 17:18
        收起回复