思维导图
引子
在大多数OS下,进程除了在并发执行,还有被动态地创建、删除。
接下来,我们来描述进程的创建和结束。
首先,进程同人一样,有自己的身份证号,其名为pid(process identifier),用来让OS进行唯一识别。相当于供内核调用的索引。
Creation
- what: 创建一个新的进程,可以覆盖旧线程,也可以另立门户
- why: 系统需要增加服务时,为完成业务而生。
例如 :web、打印机服务、ssh服务等。 - how:
- fork() ,创建一个与原来进程几乎完全相同的进程,不过可以改变初始参数和形参。整型返回值,是新进程返回值0,是父进程返回子进程的pid。
- exec() , 一个进程调用exec()加载二进制文件进入内存(销毁原来调用exec()的进程内存映像)
光有一个进程远远不够,在OS中所有的进程可以组成一家大型上市公司,进程间多存在父子关系,我们把他们当成上下雇员关系。操作系统boot启动之时(此处所涉及的细节略去,我们将在放在后面的文章中叙述),便激活了第一个进程,这个进程称为公司创始人,是所有进程的父进程。
很显然,随着时间的推移公司业务逐渐做大,创始人开始力不从心,他需要雇员来帮忙了。于是他创建了子进程(下一级雇员),子进程需要(CPU time、内存、文件、I/O设备)来干活。雇员需要的资源由社会(OS)提供、或者由创始人(父进程)提供。而创始人可以选择拉他做为合伙人(复制一份父进程资源给予子进程)、也可以把自己的盈利分一部分给他(取已有资源的子集)。
光招员工也不行,为了管理这么多人,要立规矩,正所谓无规矩不成方圆啊!工作制难道是996?No,比这还惨!生活生活,生下来就要干活。进程有两种班制:1.父进程与子进程一起运行;2.父进程等子进程结束再运行(父先等)。限制雇员的数量,毕竟雇员薪水不能超过公司盈利总和不是!父进程有权限制子进程的创建,以免使OS超载。
我们来考虑the UNIX operating system.每一个进程都有一个唯一的整型进程标识码。
新进程将由fork() 系统调用来创建,子进程将会保留原(父)进程地址空间的副本,这样使得父进程能方便地与子进程交换信息。
fork()执行完毕时,其中一个进程调用exec()加载二进制文件进入内存(销毁原来调用exec()的进程内存映像)。
父进程没什么事干,将会 调用wait() 把自己移动至等待队列,直到子进程消亡。由于对exec()的调用使用一个新程序覆盖进程的地址空间,除非发生错误,否则exec()不会返回控制柄 (return control)。
假设我们现在有两个不同的进程运行同一段程序,两个进程只有pid码是不同的,子进程将是0,对于父进程将是子进程的pid(大于0的数字)。子进程会从父进程获得权限、调度属性、当前资源(如打开的文件)。execlp()是exec()的另一种版本。父进程用wait()等待,当子进程完成或者exit()将会唤醒父进程。
Termination
- what: 操作系统收回所有该进程拥有的资源(包括物理和虚拟内存、开启的文件、I/O buffers)
- why:
1.进程过度消耗资源;
2.任务需要;
3.父进程被销毁,子进程得先被销毁。 - how:exit()结束当前进程,同时返回状态码给等待中的父进程
销毁时操作系统收回所有资源(包括物理和虚拟内存、开启的文件、I/O buffers),一个进程可以通过合适的系统调用去终结另一个进程。通常这些系统调用只被将终结的父进程所使用。用户或者失控的应用程序可以任意关掉任何一个用户级进程。同时意味着如果父进程需要关闭子进程,则需要知道它的孩子的标识码。于是这就有了进程创建新进程,新进程的标识会发送给父进程。父进程终结子进程的原因:
1.进程过度消耗资源;
2.任务需要;
3.父进程被销毁,子进程得先被销毁。
exit(1)可以正常的结束当前进程,同时返回exit status码。
等待中的父进程可以通过一个变量——来自子进程的exit status码,来知晓子进程的结束:
进程已被终止,但其父进程尚未调用wait()的进程称为僵尸进程(zombie process)。
所有进程在终止时都会转换到这种状态,但通常它们只是短暂地作为僵尸存在。一旦父进程调用wait(),就会释放僵尸进程的进程标识符及其在进程表中的条目。( All processes transition to this state when they terminate, but generally they exist as zombies only briefly. Once the parent calls wait(), the process identifier of the zombie process and its entry in the process table are released. )
孤儿(orphans)
当父进程没有激活wait()就以及被结束了,它留下来的子进程们称为孤儿。
处理:
In UNIX systems,初始化一个新进程周期激活wait()接受任何一个孤儿的exit status码,并收集、释放其的标识和进程表实体。
In Linux systems,允许其它进程继承并管理孤儿。