说明:该系类文章更多的是从从哲学视角看 操作系统 这门学科。同时也是 操作系统的学习笔记总结。因为博主 这些年主要是以研究安卓系统和 嵌入式Linux为主,因此这个系类文章也是这两个领域不可或缺的基石之一,尤其是对操作系统感兴趣的伙伴可特别关注。


4 进程

4.1 进程概论

操作系统的三大核心功能:进程管理、内存管理、文件管理。

进程:一个程序加载到内存后就变成了一个进程。即:进程=程序+执行。进程让每个用户感到自己独占CPU,是为了在CPU上实现多道编程而出现的概念。

4.2 进程模型

进程模型的三个视角:

操作系统哲学原理(04)进程原理-进程_程序计数器

  • 从物理内存分配来看:CPU在任意时刻都只能执行一个进程,而到底执行哪条指令由物理程序计数器指定,所有进程共用一个程序计数器。    
  • 从逻辑层面来看:每个进程都可以执行,也可以暂时挂起让别人执行,程序计数器可以有多个。
  • 从时间上看:每个进程必须向前推移,进程都应该完成了一定的工作量。

对操作系统而言,进程是一种抽象,目的是通过并发来提高操作系统的效率。对于进程的抽象需要做的是解决进程的存储问题和进程的调度问题。如下:

  • 多个进程同时存在于内存之上,保证其不冲突。解决方案是内存管理。
  • 多个进程之间来回切换,保证不出问题,即决定什么时候让进程使用CPU。解决方案是进程调度。    

4.3 多道编程的好处

多道编程的目的就是提高计算机的使用效率和系统的吞吐量。多道编程度数与CPU利用率之间的关系如图所示:

操作系统哲学原理(04)进程原理-进程_linux_02

注意:多道编程的度数达到12以后,CPU的利用率达到94%,这是一个临界点。之后提升的空间就很小了,因为进程切换所带来的系统消耗变得非常明显,而在此之前要求不高时几乎可以忽略不计。

相比于单道编程,系统的平均响应时间得改善,因而提高了效率。多道编程的好处有多少与每个程序的性质、多道编程的度数、进程切换消耗等均有关系。只要度数适当,多道编程还是利大于弊的。

4.4 进程的产生与消失

产生进程的事件:

  • 系统初始化(神创造人)
  • 执行进程创立程序(人生子)
  • 用户请求创建新进程(试管婴儿)

进程消亡的事件:

  • 寿终:进程运行完退出。(自愿退出)
  • 自杀:进程因为错误而自行退出。(自愿退出)
  • 他杀:被其他进程所终止,注意:一个用户可以杀死自己的进程,但是不可以杀死别人的进程,除非是超级用户。(非自愿退出)
  • 处决:因为异常而被强行终结。注意:这是被操作系统捕捉到异常后的行为(非自愿退出)    

4.5 进程的层次结构

一个进程(父进程)创建了一个新的进程(子进程)。子进程又可以创建子进程,这样子子孙孙创建下去就形成了所谓的进程树。unix/linux中称进程树里的所有进程为进程组。进程组里面的进程分布在不同的层次上,从而形成一个层次架构。(注意:windows里面没有进程组的概念,而是所有进程地位平等)

4.6 进程的状态

进程的3个典型状态:就绪、执行、阻塞,它们的关系如图所示:

操作系统哲学原理(04)进程原理-进程_unix_03

  • 阻塞-->执行这个过程是不可以的。因为阻塞进程即使被给予CPU,也无法执行,因为操作系统在调度时并不会在阻塞队列里挑选,因此,阻塞状态无法转换为执行状态。这是属于可以发生的事情;但是由于没有意义,所以不允许发生。
  • 就绪-->阻塞这个过程是不可以的。对于一个就绪状态的进程来说,它并没有执行,所以自然无法进入阻塞状态,因为操作系统只能阻塞运行的程序。这是完全不可以发生的事情,这位背了操作系统的一个原则,即一个进程只有在执行的状态下才会被阻塞。

进程的状态可以有很多,以上并不是唯一的方式,但是它们的目的都是便于操作系统管理进程。

4.7 进程与地址空间

研究进程与地址空间的关系目的是:多个进程空间共享一个高效、安全的物理内存。

4.8 进程管理

4.8.1 进程管理需要的手段

当一个进程产生时,操作系统需要为其创建记录,操作系统用于维护进程记录的结构就是进程表/进程控制块(PCB)。PCB(process control block)中存放的就是该记录的资料,不同的操作系统维护的PCB不一样。但一般都有以下几项:寄存器、程序计数器、状态字,栈指针、优先级、进程ID、信号、创建时间、所耗CPU时间、当前持有的各种句柄。这个进程表在操作系统的内核空间里如图所示:

操作系统哲学原理(04)进程原理-进程_程序计数器_04

4.8.2 进程的创建过程

@1 操作系统创建进程的步骤:

  1. 分配进程控制块(PCB)
  2. 初始化机器寄存器
  3. 初始化页表
  4. 将代码从磁盘读入到内存
  5. 将处理器状态设置为用户态
  6. 跳转到程序的起始地址(设置程序计数器)

注意:上面第5步和第6步整体上是一个原子操作,由硬件完成。

@2 进程在不同的操作系统中创建的过程也不一样:

在unix/linux中的流程:

  1.      fork(创建一个和自己一样的进程)
  2.      exec(将新的进程地址空间用另一个程序覆盖,然后跳转到新程序的起始地址,完成新程序的启动)

在windows中的流程:(仅用一步)

  1.      createprocess(创建一个新进程,把执行程序的名称当参数传递过来,创建新的页表,不需要复制)

@3 unix/linux与windows的方式各有优缺点:

  • unix/linux创建进程的过程要灵活很多,可以自我复制,也可以启动新的程序。而自我复制有时是非常有用的,比如用在web上。
  • windows创建一个新的进程简单,但是自我复制就复杂一些了。共享数据只能通过参数传递来实现。

4.8.3 进程管理要处理的问题

进程管理最大的问题就是资源分配。公平和效率都很重要,哪一个更加重要看商业需求,天平的不同倾斜将引出多种不同的进程管理模式。

4.9 进程的缺陷

进程即提高了系统的利用率,也缩短了系统的响应时间;同时,通过支持多道编程,让我们感觉每个人都拥有自己的资源。但是它同样存在缺陷。假设一个进程在执行过程中阻塞,那么整个进程都将挂起,即使进程里面有部分工作不依赖于输入数据,也无法推进。为了解决这样的问题,发明了线程。