目录
一、进程等待的基本概念
二、进程等待的重要性
三、进程等待的方法
四、获取子进程status
五、options选项
一、进程等待的基本概念
进程等待是指一个进程在执行过程中暂时停止,并等待某个条件满足后再继续执行的状态。这种等待通常是由于某些事件需要发生,或者某些资源需要被释放,才能使得进程继续执行。进程等待通常发生在多任务操作系统中,其中多个进程共享有限的资源,需要协调资源的使用和访问。
其实对于进程等待这个概念,我们是有一个基本的了解的,那么我们该如何理解进程等待的意义呢,又如何去观测这样一个过程呢?这就是本节所要提及的东西。
二、进程等待的重要性
- 之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。
- 另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
- 最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。
- 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
由此,我们就能理解为什么要进行进程等待了。
三、进程等待的方法
这里我们主要介绍两个方法:
wait方法:
pid_t wait(int*status);
返回值: 成功返回被等待进程pid,失败返回-1。
参数:输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
waitpid方法:
pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。Pid>0.等待其进程ID与pid相等的子进程。
status:WIFEXITED(status):若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。
接下来就来让我们验证验证,先写一段代码:
看一下运行结果:
按我们正常情况来说,我们的父子进程应该是同时向前运行的,但是根据结果我们可以发现,父进程并没有和我们子进程一并输出而是实实在在的等待我们的子进程结束了才进行的输出,这也印证了我们的父进程确实是在等待我们的子进程结束。
四、获取子进程status
要使用这个参数的话,我们就要好好地理解这个参数的含义和使用方法:
- wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
- 如果传递NULL,表示不关心子进程的退出状态信息。
- 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图:
这里我们只研究status的低16比特位。根据图我们可以看到低7位表示我们的信号,8到15位则表示的是我们的退出状态也就是我们的退出码。
接下来,我们修改一下代码,再来观察一下结果:
先来看看正常的结果:
接下来我们使用信号杀死这个进程,再来看看其结果:
可以发现我们的退出信号变成了9。
当然,这里需要注意的一点是,当我们的进程因为异常而终止时,其退出码时无意义的。
五、options选项
对于我们 waitpid() 的第三个参数 options。
这里需要说明的是,当我们的options为0时,就表示我们的父进程进行的是阻塞式等待,这个阻塞式等待表示的是我们的父进程在其子进程退出前一直处于持续等待的状态,一直在监听着其子进程,直到其子进程退出为止,并且在这期间,父进程是不会去做其他事的。
那如果我们想要父进程干一些自己的事情该怎么做呢?将这个参数置为WNOHANG,这就表示非阻塞式轮询式去等待我们的子进程。当然因为我们父进程需要去完成其自己的任务而不是一直等待子进程退出,所以我们需要使用一个循环,让父进程过一会就去查看一下子进程是否退出。