#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
请解释此输出。我无法理解它是如何工作的。 一步一步的分析会很棒。
答案 0 :(得分:1)
在第一个循环中,原始(父)进程分叉自身的10个副本。这些子进程中的每一个(由fork()
返回零的事实检测到)打印消息,休眠和退出。所有的孩子基本上是在同一时间创建的(因为父母在循环中做的很少),所以当他们每个人第一次被安排时,它有点随机 - 因此他们的消息的扰乱顺序
在循环期间,构建了一系列子进程ID。在所有11个进程中都有pids[]
数组的副本,但只有父进程才完成 - 每个子进程中的副本将缺少编号较低的子PID,并且其自身的PID为零。 (这并不重要,因为只有父进程实际使用此数组。)
第二个循环仅在父进程中执行(因为所有子进程在此之前已退出),并等待每个子进程退出。它等待孩子先睡10秒钟;所有其他人早已退出,所以所有的消息(第一个除外)都会快速连续出现。这里没有随机排序的可能性,因为它是由单个过程中的循环驱动的。请注意,第一个父消息实际上出现在任何子消息之前 - 父节点能够在任何子进程启动之前继续进入第二个循环。这又是流程调度程序的随机行为 - &#34; parent9&#34;消息可能出现在&#34; parent8&#34;。
之前的序列中的任何位置我看到您已经使用&#34; zombie-processes&#34;标记了这个问题。 Child0到Child8在这种状态下花费一秒或多秒,在他们退出的时间和父母对他们进行waitpid()
的时间之间。在退出之前,父母已经在等待Child9,因此一个进程基本上没有时间作为僵尸。
如果每个循环中有两条消息 - 一个在sleep
/ waitpid
之后,那么这个示例代码可能会更有启发性。颠倒第二个循环的顺序(或者等效地,将第一个循环更改为sleep(10-i)
)也是有益的。