假定下面程序执行时所对应的第一个进程标识为1000。在它的执行过程中所创建的各进程的标识是由系统按创建顺序递增加1指定的。要求回答下列问题:1)该程序在执行过程中总共会创建多少个进程?给出这些进程(用进程标识表示)间按父子关系所形成的结构。2)给出程序的显示结果,并说明理由。
#include "stdio.h"
#include <unistd.h>
int main(void)
{
int i;
int ProcessID;
int A;
A=0;
for (i=0;i<4;i++)
{
printf("Loop %d: Process ID=%d\n", i, getpid());
A=A+7;
while ((ProcessID=fork())== -1);
if (ProcessID==0)
{
printf(" Process ID=%d, A=%d\n", getpid(), A);
}
else
{
wait(NULL);
}
}
}
程序的显示结果为:
Loop 0: Process ID=3163
Process ID=3164, A=7
Loop 1: Process ID=3164
Process ID=3165, A=14
Loop 2: Process ID=3165
Process ID=3166, A=21
Loop 3: Process ID=3166
Process ID=3167, A=28
Loop 3: Process ID=3165
Process ID=3168, A=28
Loop 2: Process ID=3164
Process ID=3169, A=21
Loop 3: Process ID=3169
Process ID=3170, A=28
Loop 3: Process ID=3164
Process ID=3171, A=28
Loop 1: Process ID=3163
Process ID=3172, A=14
Loop 2: Process ID=3172
Process ID=3173, A=21
Loop 3: Process ID=3173
Process ID=3174, A=28
Loop 3: Process ID=3172
Process ID=3175, A=28
Loop 2: Process ID=3163
Process ID=3176, A=21
Loop 3: Process ID=3176
Process ID=3177, A=28
Loop 3: Process ID=3163
Process ID=3178, A=28
对输出结果的说明如下:
Loop 0: Process ID=3163
Process ID=3164, A=7
//程序运行,Process ID=3163,第一次循环,i=0,A=7,因此输出“Loop 0”。创建子进程ID=3164,严格复制父进程,i=0,A=7。父进程ID=3163调用wait()函数挂起。
Loop 1: Process ID=3164
Process ID=3165, A=14
//进入Process ID=3164,从fork()返回点开始执行,进入下个循环,i=1,输出“Loop 1”。创建子进程ID=3165,严格复制父进程,i=1,A=14。父进程ID=3164调用wait()函数挂起。
Loop 2: Process ID=3165
Process ID=3166, A=21
//进入Process ID=3165,进入下一循环,i=2,输出“Loop 2”。创建子进程ID=3166,严格复制父进程,i=2,A=21。父进程ID=3165调用wait()函数挂起。
Loop 3: Process ID=3166
Process ID=3167, A=28
//进入Process ID=3166,同理,i=3,输出“Loop3”。创建子进程ID=3167,i=3,A=28。父进程ID=3166调用wait()挂起。子进程ID=3167,由于严格复制父进程ID=3166,当前i=3,所以进程在当前循环结束返回。其父进程ID=3166中wait()函数在子进程ID=3167结束后返回。Process ID=3166的当前i=3,所以进程也在当前循环结束,其父进程ID=3165中的wait()函数在子进程ID=3166结束后返回,该进程恢复运行,当前i=2。
Loop 3: Process ID=3165
Process ID=3168, A=28
//进程ID=3165进入下一循环,i=3输出“Loop 3”。创建子进程ID=3168,i=3,A=28,严格复制夫进程ID=3165,故i=3,循环结束,进程结束。父进程ID=3165由于有子进程ID=3168结束,所以,此次循环中调用wait()函数马上返回,循环结束,进程ID=3165结束。
Loop 2: Process ID=3164
Process ID=3169, A=21
//进程ID=3164的子进程ID=3165结束,父进程ID=3164中的wait()函数返回,进入下一循环,i=2,创建子进程ID=3169,严格复制父进程,i=2,A=21,调用wait()函数挂起。
Loop 3: Process ID=3169
Process ID=3170, A=28
//进程ID=3169进入下一个循环,i=3;创建子进程ID=3170,i=3,A=28,并调用wait()挂起。子进程中i=3,循环结束,进程结束。父进程ID=3169由于有子进程ID=3170结束,其中的wait()函数返回,循环结束,进程结束。
Loop 3: Process ID=3164
Process ID=3171, A=28
//由于ID=3164的子进程ID=3169结束,其中的wait()函数返回,进入下一循环,i=3;创建子进程ID=3171,i=3,A=28,调用wait()函数挂起。子进程ID=3171中i=3,循环结束,进程结束。由于ID=3164的子进程ID=3171结束,其中的wait()函数返回,循环结束,进程结束。
Loop 1: Process ID=3163
Process ID=3172, A=14
//由于ID=3163的子进程ID=3164结束,其中的wait()函数返回,进入下一循环,i=1,创建子进程ID=3172,i=1,A=14,调用wait()函数挂起。
Loop 2: Process ID=3172
Process ID=3173, A=21
//进程ID=3172进入下一循环,i=2;创建子进程ID=3173,i=2,A=21,调用wait()函数挂起。
Loop 3: Process ID=3173
Process ID=3174, A=28
//进程ID=3173进入下一循环,i=3;创建子进程ID=3174,i=3,A=28,调用wait()函数挂起。子进程ID=3174中i=3,循环结束,进程结束。由于ID=3173的子进程ID=3174结束,其中的wait()函数返回,循环结束,进程结束。
Loop 3: Process ID=3172
Process ID=3175, A=28
//进程ID=3172的子进程ID=3173结束,其中wait()函数返回,进入下一循环,i=3,创建子进程ID=3175,i=3,A=28,调用wait()函数挂起。同上所述,进程ID=3175,3172结束。
Loop 2: Process ID=3163
Process ID=3176, A=21
//进程ID=3163的子进程ID=3172结束,其中wait()函数返回,进入下一循环,i=2,创建子进程ID=3176,i=2,A=21,调用wait()函数挂起。子进程ID=3176中i=2。
Loop 3: Process ID=3176
Process ID=3177, A=28
//进程ID=3176进入下一循环,i=3,创建子进程ID=3177,i=3,A=28,调用wait()函数挂起。同上所述,进程ID=3177,3176结束。
Loop 3: Process ID=3163
Process ID=3178, A=28
//进程ID=3163的子进程ID=3176结束,其中wait()函数返回,进入下一循环,i=3,创建子进程ID=3178,i=3,A=28,调用wait()函数挂起。同上所述,进程ID=3178,3163结束。程序退出。
我认为这个程序输出结果分析的两个重点是:
(1) fork()是对父进程的严格复制,这在子进程i和A的初始值上体现出来。而且子进程是从fork()的返回点开始运行,而不是从程序的最初开始运行。
(2) wait()的返回时间。Wait()函数的作用是挂起本进程以等待子进程的结束,子进程结束时返回。父进程创建多个子进程且已有某子进程退出时,父进程中wait()函数在第一个子进程结束时返回。