有人可以解释一下这是如何工作的吗?fork(),sleep()

Can someone please explain how this works?fork(),sleep()

#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include<stdlib.h>

int main(void)

{
  pid_t pids[10];
  int i;

for (i = 9; i >= 0; --i) {
    pids[i] = fork();
    if (pids[i] == 0) {
        printf("Child%d\n",i);
        sleep(i+1);
        _exit(0);
    }
}

for (i = 9; i >= 0; --i){
    printf("parent%d\n",i);
    waitpid(pids[i], NULL, 0);
    }
return 0;
}

这里发生了什么? sleep() 如何在 for 循环中执行?什么时候被调用?这是输出:

parent9
Child3
Child4
Child2
Child5
Child1
Child6
Child0
Child7
Child8
Child9  //there is a pause here
parent8
parent7
parent6
parent5
parent4
parent3
parent2
parent1
parent0

请解释这个输出。我无法理解它是如何工作的。 一步步分析就好了。

在第一个循环中,原始 (parent) 进程派生了 10 个自身副本。每个 child 进程(通过 fork() 返回零这一事实检测到)打印一条消息,休眠,然后退出。所有 children 基本上是同时创建的(因为 parent 在循环中做的很少),所以当它们中的每一个被第一次安排时它有点随机 - 因此他们消息的乱序。

在循环期间,构建了一个 child 进程 ID 数组。在所有 11 个进程中都有 pids[] 数组的副本,但只有在 parent 中它是完整的 - 每个 child 中的副本将缺少 lower-numbered child PID,并且其自身的 PID 为零。 (这并不重要,因为只有 parent 进程实际使用这个数组。)

第二个循环只在parent进程中执行(因为在该点之前所有child人都已经退出),等待每个child退出。它等待先睡了 10 秒的 child;所有其他人早已退出,因此所有消息(除了第一条)都快速连续出现。这里不可能随机排序,因为它是由单个进程中的循环驱动的。请注意,第一条 parent 消息实际上出现在任何 children 消息之前 - parent 能够在任何 child 进程能够之前继续进入第二个循环开始。这又只是进程调度程序的随机行为 - "parent9" 消息可能出现在 "parent8".

之前的序列中的任何位置

我看到你用 "zombie-processes" 标记了这个问题。 Child0 到 Child8 在这种状态下花费一秒或更多秒,在他们退出的时间和 parent 对他们执行 waitpid() 的时间之间。 parent 在退出之前已经在等待 Child9,因此一个进程基本上没有时间成为僵尸。

如果每个循环中有两条消息 - 一条在 sleep/waitpid 之前,一条在之后,则此示例代码可能会更有启发性。颠倒第二个循环的顺序(或等效地,将第一个循环更改为 sleep(10-i))也是有益的。