前言
在编写C
程序的时候, 通过fork
函数来创建新的进程, wait
函数来等待子进程结束.
那么就有一个问题了, 什么情况下父进程需要等待子进程结束后继续执行呢? 如果需要等待子进程结束, 那直接将操作放到父进程执行不就行了么? 反正等着也是等着.
当然, 还有一种情况, 任务A 和任务 B 是后续操作的前提条件, 并且两个任务可以并行进行, 此时确实可以父进程执行一个, 子进程执行一个, 然后父进程等待子进程完成后继续操作. 但是, 我还是觉得这个解释并不是那么完美. 这完全可以通过进程通信实现啊.
因此, 我觉得wait
函数的出现一定是有着其他用途的.
这个问题在我重翻操作系统之后有了答案.
为什么
众所周知, 进程在操作系统中运行的过程中是存在PCB
(进程管理块)模块的. 它是进程的唯一标识符, 一般保存着PID
、运行状态
、资源信息
等等.
进程在调用exit
函数退出时, 会对占有的资源进行回收. 注意, 在exit
函数回收资源的这段时间, 该进程仍然在运行中. 因此, 有一个资源是进程无法自己进行回收的, 就是PCB
. 进程要运行就需要PCB
, 而PCB
回收的前提就是进程已经不在运行了. 也就是说, 进程自己是无法回收自己的.
那么PCB
就无法回收了么? 当然不是, 该wait
函数出场了. 既然进程自己无法回收自己, 那么就由父进程负责回收咯. 因此, 这么一个等待子进程结束的函数也就有了用武之地.
顺带一提, 在子进程exit
执行结束, PCB
资源回收之前的这段时间, 子进程的状态被称为僵尸态
, 很形象了.
mac
中的进程:
debian
中的进程:
可以看到, PID
为0的进程是所有进程的父进程. 在mac
中, 所有进程都由/sbin/launchd
进行创建, debian
中则为kthreadd
. 他们的作用就是对进程进行管理和调度. 父进程通过fork
创建子进程, 之后子进程再通过exec
更换为要执行的进程.
而这个PID
为0的进程, 也是系统在运行过程中唯一一个不是通过fork
创建的进程.
但是, 还有一个问题, 那就是如果父进程没有等子进程结束呢? 子进程结束的时候, 发现其父进程早就结束了, 那它的PCB
无法回收了么? 当然不会, 这个PID
为0的祖宗进程, 或者称为root
进程会定期扫描所有的僵尸进程, 并且代替其父进程对其进行回收.