进程树/fork() 的进程数

Process tree / Number of processes for fork()

我想知道为以下代码创建的进程数。我从我的导师那里得知答案是 41,但我无法遵循同样的答案。请用流程树解释一下。

  void main() {
    for (i=0;i<2;i++){
        fork();
        if(!fork()) {
            execl("/bin/ls","ls",NULL);
            fork();
        }
        fork();
     }
     fork();
  }

这看起来像是一道作业题。如果我们给你画一个进程树,你现在可能会得到一些分数,但你不会学会如何分析一个程序,这可能会伤害到你以后。通过了解该程序的工作原理,您将了解更多信息。 (当然,这个程序是学术范例,除了学习用处不大。)

我建议用字母标记 fork 个调用。

int main(void) {
    for (int i = 0; i < 2; i++) {
        fork();          /* A */
        if(!fork()) {    /* B */
            execl("/bin/ls","ls",NULL);
            fork();      /* C */
        }
        fork();          /* D */
    }
    fork();              /* E */
}

拿纸和笔,写下发生的事情,并使用循环计数器和标记的 fork 调用画一棵树。

示例:

程序运行循环了两个循环(0和1),循环在所有进程中继续。

在parentP中循环0,forkA会创建child1.
P -(0,A)-> 1

还在循环​​0P1都会运行条件里面的forkB,创建一个每个新 child。
P -(0,B)-> 2, 1 -(0,B)-> 3.

考虑条件的含义并决定运行条件块的处理。

想想 execl 之后会发生什么,例如进程 x 执行 ls,导致 ...

一些进程(命名它们)将到达 D 并创建一个 child,所有进程将继续循环 1...

等等

要查看发生了什么,您可以在每个 fork 之后添加一些输出以显示发生了什么:哪个循环索引,哪个 fork 是进程 parent或此 fork、PID、parent PID 的 child。在 execl 之前显示哪个 PID 将要调用它。 (请注意,像 printf 这样的缓冲输出与 fork 结合使用时可能会出现意外行为,因此使用 sprintfwrite 可能更好。) 运行程序将产生可以帮助您绘制过程树的输出。甚至可以使用 graphviz 或 PlantUML 自动生成树的方式来格式化输出。这些都是进阶话题。