fork() 的输出混乱

发布于 2024-12-19 08:46:22 字数 679 浏览 3 评论 0原文

在过去的几天里,我一直在学习 fork() 函数,并做了一些实验来了解它的实际工作原理。在这样做的过程中,我发现了这段有趣的代码,但我无法理解。这是代码:

int main(int argc, char *argv[])

{
int p,m;
    p = getppid();
    printf("%d\n",p);

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}



return 0;
}

输出是:

$./a.out
6117
6460
1
user@ubuntu:~/forkbomb$ 1
1
1
1
1
1
1
1
1
1
1
1
6473

如果你向我解释一下为什么 init 的 pid 是 1 出现在输出中,那真是太好了。 如果有帮助的话,我想澄清一下,我正在尝试从给定的一个进程创建 5 个进程。那么你能告诉我正确的方法吗? 谢谢

I have been learning about the fork() function for the past few days and have been doing some experiments to know how it actually works. While doing so, I cam across this interesting piece of code which I failed to understand. Here is the code:

int main(int argc, char *argv[])

{
int p,m;
    p = getppid();
    printf("%d\n",p);

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}



return 0;
}

The output to this is:

$./a.out
6117
6460
1
user@ubuntu:~/forkbomb$ 1
1
1
1
1
1
1
1
1
1
1
1
6473

It would be really nice of you, if you explain to me why is the pid of init which is 1 appearing the output.
If it helps I would like to clarify that I was trying to create 5 processes from a given one. So can you please tell me the correct way to do so too ?
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

过期以后 2024-12-26 08:46:22

父进程首先打印其父进程的 PID。然后它继续分叉四个子项 (C1..4),然后退出。

C1 打印其父级 PID,然后继续分叉其自己的三个子级。
C2 打印其父级 PID,然后继续分叉其自己的两个子级。
C3 打印其父级 PID ...

每个分叉子级在创建它的 if 块之后继续运行,因此将创建相当多的子级。

当父进程退出时,子进程将重新设置为 init 的父进程,该进程的进程 ID 为 1。确切的输出因运行而异,具体取决于子级的安排和父级退出的确切时间/方式。

如果您只想创建五个进程,请确保子进程在完成后退出!

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
    exit(0);
}

如果您希望父级在退出之前等待其子级全部完成,您应该查看 wait 系列函数。

The parent starts by printing its parent's PID. Then it proceeds to fork four children (C1..4), and exits.

C1 prints its parent PID, then proceeds to fork three children of its own.
C2 prints its parent PID, then proceeds to fork two children of its own.
C3 prints its parent PID ...

Each forked child continues running after the if block that created it, so quite a few children will be created.

When the parent process exits, the children are reparented to init, which has process id 1. The exact output will vary from run to run, depending on exactly when/how the children are scheduled and the parents exit.

If you want to create only five processes, make sure the children exit when they are done!

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
    exit(0);
}

If you want to parent to wait for its children to all have completed before it exits itself, you should look into the wait family of functions.

眼睛会笑 2024-12-26 08:46:22

如果子进程的父进程在子进程之前退出或死亡,则该子进程称为孤儿进程并由 init 收养。这意味着子进程的 PPID(父 PID)更改为 1。这解释了您的输出,因为它来自 getppid()

为了解释显示的行数,让我们对代码行进行编号:

 1  int p,m;
 2      p = getppid();
 3      printf("%d\n",p);
 4  
 5  if(fork() == 0) {
 6      p = getppid();
 7      printf("%d\n",p);
 8  }
 9  
10  if(fork() == 0) {
11      p = getppid();
12      printf("%d\n",p);
13  }
14  
15  if(fork() == 0) {
16      p = getppid();
17      printf("%d\n",p);
18  }
19  
20  if(fork() == 0) {
21      p = getppid();
22      printf("%d\n",p);
23  }

现在让我们计算执行每个 printf() 的所有进程。第 3 行的 printf() 显然仅由原始父进程执行。第 7 行的 printf() 仅由原始父进程的第一个子进程执行,因为 fork() 在子进程中返回 0。现在,第 9 行由两个进程到达:原始父进程及其第一个子进程。它们都 fork 且它们的两个子级(即原始父级的第二个子级和原始父级的第一个子级的第一个子级)都执行第 12 行的 printf()。到达第 14 行由 4 个进程(原始父进程、其两个子进程以及原始父进程的第一个子进程的第一个子进程)组成。它们都在第 15 行生成一个子进程,所有四个子进程都在第 17 行执行 printf()。多达 8 个进程到达第 19 行。每个进程都会分叉,并在最小的进程中生成 8 个子进程生成执行第 22 行最后的 printf()

第一个 printf() 执行了 1 次。
第二个 printf() 执行了 1 次。
第三个 printf() 执行了 2 次。
第四个 printf() 执行了 4 次。
第五个 printf() 执行了 8 次。

总共 16 个,与您的输出一致。显示的一些 PPID 等于 1,表明给定的父进程执行得非常快,以至于子进程在到达给定的 printf() 之前就被 init 采用了。其他值大于 1,表示当子进程中到达 printf() 时,给定进程的父进程仍在运行。程序的多次执行很可能会导致不同的输出。

因此,您不会创建 4 个子进程,而是创建 15 个。这是因为您的子进程从生成它们的 fork() 返回后继续执行。这意味着某些 fork() 不仅会由原始父进程执行,还会由其子进程执行,从而创建级联的新进程。如果您只想创建 4 个子级,则应确保剩余的分叉仅发生在父级中。

If child process's parent exits or dies before the child, then the child is called an orphaned process and is adopted by init. This means that PPID (parent PID) of the child changes to 1. This explains your output since it comes from getppid().

To explain the number of lines that was displayed, let's number the lines of code:

 1  int p,m;
 2      p = getppid();
 3      printf("%d\n",p);
 4  
 5  if(fork() == 0) {
 6      p = getppid();
 7      printf("%d\n",p);
 8  }
 9  
10  if(fork() == 0) {
11      p = getppid();
12      printf("%d\n",p);
13  }
14  
15  if(fork() == 0) {
16      p = getppid();
17      printf("%d\n",p);
18  }
19  
20  if(fork() == 0) {
21      p = getppid();
22      printf("%d\n",p);
23  }

Let's now count all the processes that executed each printf(). The printf() on line 3 was obviously executed only by the original parent process. The printf() on line 7 was only executed by the first child of the original parent process since fork() returns 0 in the child. Now, line 9 is reached by two processes: the original parent and its first child. Both of them fork and both of their children (i.e. second child of the original parent and the first child of the first child of the original parent) execute the printf() on line 12. Line 14 is reached by 4 processes (the original parent, its both children and the first child of the first child of the original parent). All of them spawn a child on line 15 and all the four children execute the printf() on line 17. As many as 8 processes reach line 19. Each of them forks and 8 resulting children in the youngest generation execute the final printf() on line 22.

First printf() is executed 1 time.
Second printf() is executed 1 time.
Third printf() is executed 2 times.
Fourth printf() is executed 4 times.
Fifth printf() is executed 8 times.

This is 16 in total and is consistent with your output. Some of the PPIDs displayed are equal 1 indicating that a given parent executed so fast that the child was adopted by init before it reached a given printf(). Others are greater than 1 indicating that the parent of a given process was still running when the printf() was reached in the child. It is extremely likely, that multiple executions of the program will result in somewhat different output.

Thus, you do not create 4 child processes, but 15. This is due to the fact that your children continue executing from when the fork() that spawned them returns. This means that some of the fork()s will be executed not only by the original parent, but also by its children, creating a cascade of new processes. If you want to create only 4 children, you should make sure that remaining forking happens in the parent only.

滥情稳全场 2024-12-26 08:46:22

您错过的是,当您分叉时,有 2 个进程具有相同的代码副本,从您分叉的点继续。

父级返回子级的 pid,子级返回 0。
因此,您将分叉 16 个进程(4 个阶乘),因为每次分叉时,进程数量都会增加一倍。

如果您在末尾添加 sleep() 以确保父进程挂起足够长的时间,那么您将在子进程中获得实际的父进程 pid(只需在返回之前添加 sleep(2) )。

我的输出是:

> ./x
19291
21686
21686
21687
21688
21687
21687
21688
21689
21691
21690
21689
21695
21686
21686
21694

What you missed is that when you fork there are 2 processes with the same copy of the code continuing from the point where you forked.

The parent gets pid of child returned and the child gets 0 returned.
So you are forking 16 processes (4 factorial) because at each fork you are doubling the number of processes.

If you add sleep() at the end to make sure that the parent processes hang around long enough then you get the actual parent pid in child (just add sleep(2) before return).

My output is:

> ./x
19291
21686
21686
21687
21688
21687
21687
21688
21689
21691
21690
21689
21695
21686
21686
21694
緦唸λ蓇 2024-12-26 08:46:22

首先,1 来自已经退出的父进程。然后父进程成为系统 init 进程 1

如果您也对得到的 1 数量感到恼火:
初始进程分叉了 4 个子进程,第一个子进程分叉了 3 个子进程,有两个子进程各分叉了 2 个子进程,三个子进程分叉了 1 个子进程,还有四个子进程不再进一步分叉。这使得 1+1+4+3+2+1+4 = 总共 16 个进程。

First of all, the 1's come from the parent process(es) having exited already. The parent then becomes the system init process, 1.

If you are also irritated by the number of 1s you get:
The initial process forks 4 children, the first child of this forks 3, there are two children that fork 2 each, three children that fork 1. and four that don't fork any further. That makes 1+1+4+3+2+1+4 = 16 processes total.

痞味浪人 2024-12-26 08:46:22

该程序将在四个 fork() 部分中创建 1 + 2 + 4 + 8 = 15 个进程(如果加上原始进程则为 16 个进程)。也许您想要做的是这样的:

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
} else
    return 0;

如果其父级已经消失,getppid() 将返回 1。由于我们不知道系统如何安排这些进程,因此您可以看到这可能会在您的程序中发生。

This program would create 1 + 2 + 4 + 8 = 15 processes in the four fork() parts(16 if we plus the original one). Maybe what you want to do is something like this:

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
} else
    return 0;

getppid() would return 1 if its parent had been gone. Since we don't know how the system would schedule these processes, you can see this could happen in your program.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文