理解 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()
之后子进程继承了i
的current值。每次调用 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 行。我认为这回答了你的第二个问题。
我正在阅读 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()
之后子进程继承了i
的current值。每次调用 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 行。我认为这回答了你的第二个问题。