试想这样的场景:

你和你的树懒一起到外面吃午餐,你吃的比较快,但是要等待树懒吃完后才能一起走。

整个过程如下:

你和树懒开始就餐;

你需要等待树懒吃完后再一起走。

以进程等待代替整个过程, 对于上述过程可以理解为创建子进程->等待子进程退出->主进程退出。


就绪转执行

处于就绪状态的进程,当进程调度程序为之分配了处理机(CPU)后,该进程便由就绪状态转变成执行状态。

执行转就绪

处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完或更高优先级的进程抢占而不得不让出处理机

于是进程从执行状态转变成就绪状态。

执行转等待

正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成等待状态。

等待转就绪

处于阻塞状态的进程,若其等待的事件已经发生,于是进程由等待状态转变为就绪状态。

执行转退出

进程执行完毕,撤销而退出。

其中,进程等待是进程控制的关键,也是重点。

进程等待的原因


进程控制块(PCB)是进程在整个运行过程中非常重要的一个数据结构,里面包含以下几种信息:

进程描述信息;

进程控制信息;

资源信息;

现场保护信息。

进程终止或者退出的时候,进程会关闭所有文件描述符,释放用户空间分配的内存,但是PCB却会暂时保留。

假如进程正常终止, PCB 里面就记录进程的退出状态;如果是异常终止,那么 PCB 里面存放着导致该进程终止的信号。

子进程的退出状态必须由父进程回收.

也就是说,父进程必须得等待子进程退出后再自己退出,否则子进程会变成僵尸进程

(没有任何可执行代码,不会被调度,只有一个进程描述符用来记录退出的状态,除此之外不再占用其他任何资源)。

wait函数
#include<sys/types.h> 
#include<sys/wait.h>
pid_t wait(int* status);

参数: status ,整型指针,指向的地址即存放退出子进程的退出状态,不关心可以设为 NULL。

等待方式是阻塞式等待,一旦子进程退出,父进程就会立刻收到 SIGCHLD 信号。

注意:父进程调用 wait,是等待任意一个已经退出的子进程,只要是有子进程退出了,那么就获取子进程退出状态然后返回。


应用示例:

树懒吃东西.png


参数详解:

pid:希望等待退出的子进程的进程号;

status:整型指针,指向的地址即存放退出子进程的推出状态,不关心可以设为 NULL;

options:设置为 0,代表阻塞式等待,如果设置为 WNOHANG, waitpid 发现没有已经退出的子进程可以收集

就返回 0,此时是非阻塞式等待。

返回值:

返回 0 表示没有已经退出的子进程;返回正值,表示有已经退出的子进程。


编程要求

在主函数的最开始会初始化一个全部变量g_i4event为0。

编程任务是补全右侧代码片段中两段Begin至End中间的代码,具体要求如下:

创建子进程,创建完后,将 g_i4event 置为 1;

子进程等待 3s ,然后子进程退出;

父进程等待一秒,将 g_i4event 置为 2;然后等待子进程退出,父进程获取子进程退出的状态后将 g_i4event 置为 3;

process_wait采用 wait 函数,process_waitpid 采用 waitpid 函数。

以下是测试样例:

测试输入:1

预期输出:

You and Sloth go to have lunch!

You have finished your meal!You need wait the sloth

Sloth have finished your meal! You and sloth will go home.

测试输入:2

预期输出:

You and Sloth go to have lunch!

You have finished your meal!You need wait the sloth

Sloth have finished your meal! You and sloth will go home.



本题解答:

树懒吃东西.jpg