理解POSIX - fork()

时间:2016-06-09 16:29:25

标签: c operating-system fork posix

我正在阅读fork函数以及它如何创建新进程。以下程序运行正常并打印here十六次,但是,我无法理解执行流程:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h> 

int main() 
{ 
    int i; 
    for (i = 0; i < 4; i++) { // line no. 12
        fork();               // line no. 13
    }
    printf("%s\n", "here");
    return 0; 
}

在我看来,这个程序有两种方式可以被视为:

第一种方法:fork()总共被召唤四次。如果我用四次调用fork()函数替换循环,事情似乎已经到位,我理解为什么here打印2 ^ 4次。

第二种方法:fork()完全从调用它的位置产生一个新进程,并且每个子进程都有自己的局部变量。所以,行后没有。 13,这些子进程中的每一个都看到循环结束(}),然后它们转到第0行。 12.因为,所有这些子进程都有自己的局部变量i设置为0(可能i设置为某个垃圾值?),它们都会再次分叉。同样,对于这些子进程,其局部变量i设置为0.这应该会产生fork bomb

我肯定错过了我的第二种方法,有人可以帮忙吗?

感谢。

3 个答案:

答案 0 :(得分:3)

你的第二种方法是不对的。因为在fork()之后子进程继承了i当前值。它不会在每次调用0时设置为fork(),也不会有垃圾值。所以,你的代码不能有叉炸弹。它是一个局部变量的事实是无关紧要的。 fork() 克隆几乎所有内容和子进程都与其父进程相同,除了POSIX手册中指出的某些内容。

为了便于解释,我将循环次数减少到2,并假设所有fork()次呼叫都成功:

   for (i = 0; i < 2; i++) {
        fork();
    }
    printf("%s\n", "here");

1)执行i=0fork()时,现在有两个进程。称他们为P1和P2。

2)现在,每个P1和P2进程继续i = 0循环并将i增加到1. for循环条件为真,因此每个进程生成另外两个进程并且总计4.称他们为P1a&amp; P1b和P2a&amp; P2B。所有4个进程现在都有i = 1并将其增加到2(因为它们继续循环)。

3)现在,所有4个进程的值i为2,并且循环条件在所有进程中都为false,&#34; here&#34;将被打印4次(每个过程一次)。

如果有帮助,您可以将for循环转换为while循环以及两个进程从{{1}返回的i递增的方式可能会变得更清楚:

fork()

答案 1 :(得分:1)

你的第一种方法是对的。
这是一个相当无聊的答案,所以我会给你所有技术细节。

调用fork时会发生以下几件事:

  • 创建了一个新流程(&#39;孩子&#39;)
  • 父级的堆栈是重复的,并分配给子级。
  • 子项的堆栈指针设置为父项的堆栈指针。
  • 将子项的PID(进程ID)返回给父项。
  • 归零给孩子

在函数内声明 的变量存储在堆栈中,因此从相同的值开始,但共享。
声明外部一个函数(在顶层)的变量不在堆栈中,因此在子/父之间共享。

(其他一些事情有或没有重复;有关详细信息,请参阅man fork。)

所以,当你运行代码时:

    what happens                    # of processes  
1. the parent forks.                2  
2. the parent and it's child fork.  4  
3. everyone forks                   8  
4. everyone forks                   16  
5. everyone prints "here".          16

你最终得到了16个流程,而且这里的“&#39;十六次。

基本上,

if(fork() != 0) {
    parent_stuff();
} else {
    child_stuff();
}

答案 2 :(得分:0)

使用以下代码,您可以轻松了解fork如何创建变量i的值:

for (i = 0; i < 4; i++) {
    printf("%d %s\n", i, "here");
    fork();              
}

如您所料,子进程复制了父进程的值,因此我们得到0行,其中i = 0; i = 1的2行; i = 2的4行和i = 3的8行。我认为这可以回答您的第二个问题。