理解 POSIX - fork()

Understanding POSIX - fork()

我正在阅读 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,这些子进程中的每一个都看到循环的结尾(})并且它们转到第 1 行。 12. 因为,所有这些子进程都有自己的局部变量 i 设置为 0(也许 i 设置为一些垃圾值?),它们都再次 fork。对于这些子进程,它们的局部变量 i 再次设置为 0。这应该导致 fork bomb.

我的第二种方法肯定遗漏了一些东西,有人可以帮忙吗?

谢谢。

你的第二种做法不对。因为在fork()之后子进程继承了icurrent值。每次调用 fork() 时都不会设置为 0,它们也没有垃圾值。所以,你的代码不能有分叉炸弹。它是一个局部变量这一事实是无关紧要的。 fork() clones 几乎所有东西和子进程与其父进程相同,除了 POSIX 手册中提到的某些事情。

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

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

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

2) 现在,每个 P1 和 P2 进程继续 i=0 循环并将 i 递增到 1。for 循环条件为真,因此它们各自产生另外两个进程总共 4 个。称它们为 P1a 和 P1b 以及 P2a 和 P2b。所有 4 个进程现在都有 i=1 并将其递增到 2(当它们继续循环时)。

3) 现在,所有 4 个进程的 i 的值为 2,并且 for 循环条件在所有进程中都为 false,并且 "here" 将被打印 4 次(每个进程打印一次) .

如果有帮助,您可以将 for 循环转换为 while 循环以及 i 如何通过 both 进程返回每个 fork() 可能会变得更清楚一点:

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

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

调用 fork 时,会发生几件事:

  • 创建了一个新进程('the child')
  • parent的堆栈被复制,并分配给child。
  • child 的堆栈指针设置为 parent 的堆栈指针。
  • child的PID(进程ID)返回给parent。
  • 零返回 child

内部函数声明的变量存储在堆栈中,因此以相同的值开始,但共享。
外部 函数(在顶层)声明的变量不在堆栈中,因此在child/parent.

之间共享

(其他一些内容重复或不重复;有关详细信息,请参阅 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 个进程,'here' 这个词出现了 16 次。

基本上,

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

使用下面的代码,你可以很容易地看到fork是如何创建变量i的值的:

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

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