【问题标题】:How is fork() working when children fork?当孩子分叉时 fork() 是如何工作的?
【发布时间】:2011-11-28 09:36:56
【问题描述】:

我已经执行了一段代码。如下图:

#include<stdio.h>

main() {
int i=0;
fork();
printf("The value of i is:%d\n",++i);
fork();
printf("The value of j is:%d\n",++i);
fork();
wait();
}

我得到以下输出:

The value of i is:1
The value of j is:2
The value of i is:1
The value of j is:2
The value of j is:2
pckoders@ubuntu:~$ The value of j is:2

谁能解释一下 fork() 和 wait() 函数在这里扮演什么角色?

【问题讨论】:

  • 手册页的哪一部分您不明白?究竟是什么问题?
  • @johannes,那么我们可以从 SO 中删除大多数 API 问题吗?

标签: c unix fork wait


【解决方案1】:

程序生成进程树。在每个fork,这棵树都会分成两截。如果你抓一张纸,画这棵树并不难;由于您使用前缀++,唯一困难的是获得正确的i 值。如果你让每个进程sleep 结束几秒钟,你也可以使用pstree 程序观察树。

然后每个进程运行wait 系统调用,由waits for any one of its child processes(进程树中的子节点)完成。

【讨论】:

  • 不是第一个,如果我们想学究气,但是任何个孩子,对吧?
  • @AmigableClarkKant:严格来说,是的。更新了答案。
  • 我认为一个关键词是它等待一个孩子。这就是它在打印最后一行之前退出的原因。
【解决方案2】:

在第一个 fork() 之后有两个进程(当前和它的精确副本,子进程),它们都打印 1。

这两个进程中的每一个都在第二次 fork() 调用中复制了自己,并且有 4 个进程,每个进程都打印 2。

它们的输出是随机顺序的,就像并行执行一样。

【讨论】:

  • 谢谢尤金。我理解了流程。再次感谢您的关心。
【解决方案3】:

fork() 调用实际上是一个分叉。完成后,您将拥有 2 个具有精确堆栈的精确进程,并且所有描述符都引用相同的对象。您可以通过返回值来区分它们。对于子进程 fork() 返回 0,对于父 - 子进程 ID。

所以

main() {
int i=0;
fork(); 
// at this point you are having 2 processes. stdout and stdin are basically just dupplicates.
//          (P)
//        /     \
//     (P)       (C)
//   prints1    prints 1
printf("The value of i is:%d\n",++i); // so 2 processes with print 1
fork();
// now you are having 4 processes( both parent and children forked)
//                   (P)
//                 /     \
//               /         \
//           (P)            (C)
//         /     \         /   \
//      (PP)     (PC)    (CP)  (CC)
//   prints 2  prints 2  prints 2  prints 2
printf("The value of j is:%d\n",++i);
fork();
// now 4 processes are forking. now you have 8 processes
//                                   (P)
//                                /       \
//                            /              \
//                         /                    \
//                   (P)                           (C)             
//                 /     \                       /     \           
//               /         \                   /         \          
//          (PP)           (PC)             (CP)          (CC) 
//         /     \        /     \          /    \       /     \        
//     (PPP)    (PPC)  (PCP)   (PCC)   (CPP)   (CPC)  (CCP)  (CCC)   

wait();
}

【讨论】:

  • GreenScape ,我对你用如此简洁的图表解释这个概念的方式感到非常满意。我得到了它。感谢您的关心和回复。但是让我再清楚一个疑问,即为什么它交替打印 i 和 j 的值?在第一次 fork() 之后,它应该立即依次显示 i 的值两次。但它在打印一次 i 的值后显示 j 的值...
  • 这完全取决于操作系统的调度程序。想象一下进程 P 分叉成 P 和 C。CPU 与 P 进程一起工作。它打印 1. 转到下一个叉子。执行它。进程 PP 打印 2。调度程序切换到进程 C,现在 CPU 与 C 一起工作。C 打印 1。依此类推...
  • 如果没有wait()会发生什么?
  • 您可能会看到完全不同的进程树。而不是等待每个进程将尽快退出。这取决于哪个进程有机会先退出。
【解决方案4】:

分叉进程以树状方式创建子进程。将每个分叉视为二叉树的不同层。当你不发出 fork() 时,你只有一个根节点的进程树。当你发出一个单独的 fork() 那么你现在有一个具有两层的二叉树,第一层将包含父进程,第二层将包含两个进程 - 父进程和子进程。

当你想知道你手头有多少进程时,只需继续构建二叉树/进程树,看看最后一层有多少节点,最后一层就是进程的当前状态/ tree.Wait 函数使您的父进程等待子进程完成执行。在您不想要僵尸进程的应用程序中,您需要发出等待,否则这些僵尸进程将继续占用系统...link.

请记住,当您总是希望父母在孩子之后完成时,等待也很有用。分叉并不总是给出相同的输出,顺序是混乱的,因此要始终获得相同的输出,请使用 wait()。要等待特定子进程,请使用 wait(pid),其中 pid 是特定子进程的 pid,该 pid 可以通过子进程空间内的 getpid 获得。

【讨论】:

  • –1 表示所有可笑的省略号和“u”的愚蠢,以及其他所有使这成为完全不可读的非答案的东西。使用正确的段落、拼写和标点符号以标准英语重写,此反对票将被删除。
猜你喜欢
  • 2013-02-12
  • 2019-04-11
  • 2018-08-10
  • 2022-10-22
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 1970-01-01
  • 2013-12-22
相关资源
最近更新 更多