2011-02-15 94 views
3

我正在探索父进程& UNIX中的子进程概念。我写了这个小代码,认为x no。或进程将被创建。但它创造了一个不同的号码 -C进程fork()

#include <stdio.h> 
#include <unistd.h> 
#include <sys/types.h> 

int main(int argv, char *argc[]) 
{ 
    int i; 
    pid_t childpid; 

    for(i=0; i<3; i++) 
    { 
     childpid = fork(); 
     if(childpid == -1) 
     { 
      perror("Failed to Fork"); 
      return 1; 
     } 

     if(childpid == 0) 
      printf("You are in Child: %ld\n", (long)getpid()); 
     else 
      printf("You are in Parent: %ld\n", (long)getpid()); 
    } 
    return 0; 
} 

OUTPUT: 
You are in Parent: 30410 
You are in Child: 30411 
You are in Parent: 30410 
You are in Child: 30412 
You are in Parent: 30411 
You are in Parent: 30410 
You are in Child: 30413 
You are in Child: 30414 
You are in Parent: 30412 
You are in Parent: 30411 
You are in Child: 30415 
You are in Child: 30416 
You are in Parent: 30413 
You are in Child: 30417 

据我所知,在fork()情况家长或孩子可能会在执行偏好。这并不困扰我,困扰我的是正在执行的进程的数量。为什么是14?而不是一些2^n的数字,这是如果我们执行fork(); fork(); fork()即叉子一个接一个地会发生什么。

我错过了什么?

UPDATE:一个更明确 -

fork功能复制父 存储图像,使接收 父的地址空间 副本的新进程。

这是什么意思?是否意味着 -

  1. 子进程在fork()声明后开始执行?
  2. 子进程获取父进程变量的副本?所以如果x=3以上的fork,将子进程看到这个x为3吗?
+1

要更新:是的,两个进程从fork返回,这就是主意。在那个时候,它们的内存空间仅在`fork`的返回值上有所不同。 – rlibby 2011-02-15 04:31:45

+1

这意味着它说 - 在fork之后,子进程拥有父进程的内存副本,所以子进程的所有代码和堆栈以及寄存器和变量都与父进程的全部相同,唯一的例外是返回来自fork的值,它存储在childpid中。所以,1和2的答案都是肯定的。 – 2011-02-15 11:52:44

回答

12

8个进程正在执行,只是由于循环,它们中的一些打印了不止一次。

如果排序输出:

You are in Parent: 30410 
You are in Parent: 30410 
You are in Parent: 30410 

You are in Parent: 30411 
You are in Parent: 30411 
You are in Child: 30411 

You are in Parent: 30412 
You are in Child: 30412 

You are in Parent: 30413 
You are in Child: 30413 

You are in Child: 30414 

You are in Child: 30415 

You are in Child: 30416 

You are in Child: 30417 

,那么你可以看到,只有8独特的进程ID。

原因很微妙。由于子进程从父进程继承(几乎)所有内容,因此它也会获得当前的循环状态。我说“差不多”,因为某些事情是不同的,比如PID(显然),父PID(同样明显)以及某些资源限制(取决于操作系统)。

因此,过程0时i == 0分成两部分。他们的下一个周期在i == 1。这两种方法都将在下一个周期分配i == 2。等等。

如果您查看下图,您可以看到创建过程。

 ____A____ 
    / | \ 
    B_ C_ D 
    | \  \ 
    E F  G 
    \ 
     H 

线条/|\表示在其中i0,分别12点叉子。

请注意,一个过程(如E)是从父母创建的,其中i == 1仅与i == 2分叉。换句话说,它是用|创建的,所以它的下一步是\

类似地,用/i == 0)创建B将仅叉|i == 1)和\i == 2)。

如果您对其他叉子信息感兴趣,请参阅我的大量散文here以及Linux here下不同叉子选项的内部细节。

1

我认为,之所以你看到这么多的进程可以创建的,当你fork一个子进程,它在for循环的中间。因此,在它打印出它是一个孩子之后,它将继续循环并分叉自己的孩子。

为了解决这个问题,只是有孩子退出打印,他们是照看孩子:

if(childpid == 0) { 
    printf("You are in Child: %ld\n", (long)getpid()); 
    exit(0); 
} 

顺便说一句,这也解释了为什么你看到2个ñ过程为一个循环做ñ迭代。在每次迭代中,每个进程分成两个进程,然后运行其余的循环迭代。这意味着每次迭代都会使进程的数量增加一倍,因此在n次迭代之后,您将看到2个n进程。

希望这会有所帮助!

2

当你调用fork()时,程序开始的地方是在处理过程中。所以,你必须

I = 0,2个进程
I = 1,4个流程
i = 2,8过程

rlibby在他的评论中指出,我忘了考虑到一个事实,即来自每个原始通行证的过程都是总计的一部分。所以我的数学错了。它应该是:

I = 0,1个处理+ 1新的(2个)
I = 1,2个工序+ 2个新的(共4个)
I = 2,4流程+ 4新(总共8个)

+0

错了。上面有8个进程*总计*。你已经给出了每个步骤中有多少个过程具有i的值,但是达到i = 2的过程中的一半也具有i = 1,其中一半具有i = 0,并且其中一半(即1)是原始过程。 – rlibby 2011-02-15 04:26:20

1

只有8个进程。统计唯一的进程ID。

0

我认为添加一个break而不是添加一个exit(0)也可以。