在计算机中,进程就是一段程序的执行。
进程包括:
1 )执行这段程序所需要的代码
2 )执行程序所需要的相关数据
3 )操作系统管理进程所需要的信息 —— 进程控制块
ok 了解了进程的基本概念,接下来就要去了解进程的具体组成结构和操作系统如何去控制进程
在看进程的状态之前,先复习一下,进程在系统中如何运作。
操作系统通过一种分时机制实现多进程的并发执行。这里用到了并发这个词而不是并行,是因为针对单处理器的计算机来说,从来就不会有并行状态发生,一个处理器同一时间内只能处理一段代码,也只能完成某一个任务,是不可能实现任务的并行执行的。
为了提高计算机的用户体验,也为了合理的利用计算机资源,让 CPU 在最大限度下处于一直工作的状态,操作系统通过执行一种叫做 轮转的方式,为每一个进程分配一个最大运行时间(时间片)造成一种多进程并发执行的状态。
所以,在某一个时间点上,看似同时在运行的多个进程,只有一个,或几个(多处理器)进程在运行,其他的进程处于其他状态。
那么进程到底拥有几个状态?
进程的状态会因为不同操作系统的实现不同而略有改变,但最基础的是五种状态:
1. 新建状态:刚刚创建进程,操作系统还没有把它加入到可执行的进程组之中。(也就是,进程虽然创建,但是尚未运行,尚未加入任何队列之中。 —— 队列的概念稍后会提出)
2. 就绪态:进程做好了准备,等待分配处理器。
3. 阻塞态:进程在某些事件发生之前不能执行:如 IO 操作
4. 运行态:该进程获得了时间片,拥有控制处理器的权利,正在运行相关程序。
5. 退出:操作系统从可运行进程组中释放进程,或者他自身的原因停止了,或者因为某些原因取消。
解释:
为什么会有阻塞状态?
因为计算机存在着个各个部位运行速度的不均衡,处理器的运算速度常常是 IO 设备的上千倍上万倍,有些 IO 设备的速度尤其慢比如打印机。如果某些进程需要使用 IO 设备的返回结果,那么处理器必须等待 IO 设备完成任务,并返回执行结果,在这期间处理器完全没有工作,这就造成了计算机资源的浪费。因此,操作系统实现了一种阻塞机制,当一个进程需要用到 IO 等耗时的工作时, 进程阻塞。在 IO 完成时会产生一个 IO 中断,告诉操作系统,这个事件已经完成,刚才那个或者那些需要等待的任务可以继续进行了,操作系统会根据分派器决定哪一个进程将会继续执行。
进程如何开始?
通常有 4 个事件会导致创建一个进程。
1)新的批处理作业
2)交互登陆
3)操作系统因为提供一项服务创建
4)由现有的进程派生
进程如何终止的?
有很多行为都能造成系统的终止,进程在任何状态下都能被终止。
终止的原意可能是,交互系统下用户的终止,也可能是自身产生的错误或者硬件产生的错误。
什么是抢占?
抢占这术语被定义为收回一个进程正在使用的资源。这是一种可能发生的运行 -> 就绪状态的转换原因。当阻塞队列中拥有一个优先级高于当前执行的进程,当阻塞事件发生,高优先级进程恢复到可运行状态,就有可能抢占运行进程的资源,让当前进程变成就绪状态。
线程执行轨迹
中断发生后程序计数器(PC) 重新赋值程中断处理程序 , 中断处理程序会委托分派器决定接下来执行的进程。
什么是队列?
队列是操作系统维护进程执行的数据结构,使用FIFO 的结构保存即将执行的任务。
最基础的队列由一个就绪队列和一个阻塞队列组成,当一个进程的时间片用尽且没有阻塞的话会被插入就绪队列,并且从就绪队列中取出一个新的进程进行运行。当一个进程被阻塞,会被放入阻塞队列。这样有一个很明显的缺点,当发生一个阻塞事件,操作系统会扫描整个阻塞队列,将等待这个事件的进程放入就绪队列,一个真正的操作系统阻塞队列中常常有很大量的阻塞进程,这样会导致效率十分的低下。
所以,一般来说,等待一个事件的阻塞进程放入单独的队列之中 , 当事件发生 , 整个队列放入就绪队列之中。
同理,多优先级也会维持多优先级队列以方便管理。
除了刚才说过的五种进程状态,还有一类状态叫做挂起态。挂起态并不是一个状态,而是一对。首先解释一下什么叫挂起态。
挂起态的产生还是因为计算机资源的不足,计算机内存是一种昂贵的资源,内存大小的发展速度完全跟不上程序常驻内存大小的发展速度,所以这就极大地限制了同时能够运行的进程的数量。而且,计算机 IO 的速度比起 CPU 计算的速度还是太慢,在某个时间点,队列中可能完全没有就绪状态的进程,全部都在等待 IO 。因此操作系统常常加入一个挂起态,用来“驱逐”等待 IO 的进程,提供足够的空闲内存供更多进程使用。
这里涉及到一个交换的概念。交换是一个 IO 操作,当内存中所有的进程都处于阻塞状态时,操作系统可以把其中一个进程置于挂起状态,将其内存占用转移到磁盘,内存释放的空间可以被调入另一个进程使用。
接着思考挂起的问题,当内存拥有足够的空间,这时候可以选择开启一个新的进程或者从挂起状态的进程中选择一个用来运行。但是挂起状态的进程在挂起前是阻塞的,如何判断他现在可否执行呢?因此要为挂起态的进程再进行细分,以确定被挂起的进程是否是就绪的。这样就诞生了 2*2 = 4 种不同的状态
就绪态
阻塞态
挂起阻塞态
挂起就绪态
当一个阻塞事件发生,等待此事件的阻塞进程从阻塞队列进入就绪队列,等待此事件的阻塞挂起进程进入就绪挂起状态。当内存中拥有足够的空间可以容纳一个新的进程时,就绪挂起状态的某一个进程就有可能重新回到就绪状态运行。
这里所说的挂起状态的转化,是在简化了操作系统实际的转化过程之后总结的。
在实际的操作系统中,是否挂起还考虑到优先级问题,如果就绪挂起队列某进程中拥有比就绪队列中更高的优先级,那么就绪队列中也有可能会有进程被交换到挂起状态,以供更高优先级的进程继续执行。
如果这个过程中涉及到虚拟内存,设计的话会更加复杂,留作以后讨论。
在学习进程的管理之前要了解一下操作系统为了管理进程维护管理的资源
操作系统维护着4 中不同的表:
内存:用于追踪内存和外存。内存表包括以下信息:
1.分配给进程的内存
2.分配给进程的外存
3.内存块或者虚拟内存块的任何保护属性。
4.管理虚拟内存所需要的任何信息
IO : IO 表管理的计算机系统中的 IO 设备和通道
文件:提供文件是否存在,文件在外存中的位置
进程表 剩余部分将讨论的就是进程表。
操作系统要对进程进行管理,首先要知道进程的位置,再者要知道管理时所需要的进程属性。
一个进程的物理组成是程序、数据、栈、属性所占用的内存。这些元素组成了进程映像。
进程属性有可以细分为一下三类:
进程标识信息:用于标识一个进程的属性,包括(唯一标识符、父进程标识符、用户标识符)
处理器状态信息:用于进程切换的时候保存运行时处理器状态的属性。
进程控制信息:控制和协调各种活动需要的额外信息。
进程控制块被一个统一的处理例程访问,目的是控制对进程控制块的访问,以保护进程控制块。
执行模式
大多数操作系统至少支持两种执行模式,有些指令只能在特权模式下执行,有些内存区域也只能在特权模式下才能访问到。
非特权态常被称作用户态,特权态被称作系统态或者内核态。
使用不同执行状态的原因是为了保护系统,不让用户去执行特定的可能影响系统的指令。
处理器如何判断当前是什么执行模式?
PSW 程序状态字(处理器的一部分)中有一位表示执行模式,当用户调用一个系统服务或者中断处于发了系统例程的执行时,执行模式设置成内核态,返回时会被设置成用户态。
进程的创建
1.给进程分配一个唯一进程标识符
2.给进程分配空间
3.初始化进程控制块
4.设置正确的链接。将新的进程放入正确的调度队列之中。
5.创建或者扩充其他数据结构
进程的切换
分析一下进程的切换,进程的切换在宏观上(相对宏观)就是操作系统指定另一个进程为运行态,并且把控制权交给这个进程。但这会引发很多新的问题:
1.什么时候切换进程?
2.模式切换和进程切换有什么区别和联系?
3.切换一个进程必须对数据结构做些什么?
本片为文章剩下的部分就是解决这几个问题
何时切换进程?
简单点说,只要操作系统有控制权,就能切换进程。
操作系统会在以下时间从正在运行的进程中获取控制权:
1.中断 常见中断(时钟中断(时间片用尽), IO 中断( IO 完成),内存失效(缺页,和 IO 同理,至于什么叫缺页,虚拟内存会涉及到这个名词))
2.陷阱:正在执行的进程所发生的错误
3.系统调用:显式的请求
模式切换
如果存在一个未处理的中断,会发生以下的工作
1.把程序计数器置成中断处理程序开始的地址
2.从用户态切换到内核态,使得中断处理代码可以包含特权指令。此时,被中断的进程上下文保存在被中断程序的进程控制块中。
进程切换
很明显,进程转换和模式转换不同,模式切换可以不改变正在运行的进程状态,在这种情况下保存和恢复上下文环境只需要很少的开销,但如果当前正在运行的进程转换成另一个状态,则操作系统必须使其环境发生实质的变化。
完整的切换过程如下:
1.保存处理器上下文环境
2.更新当前处于运行态的进程控制块,将其状态改变到另一状态。
3.将进程移动至相关队列
4.选择另一个进程
5.更新所选择进程的控制块,将其状态变成运行态。
6.更新内存管理的数据结构
7.恢复被选择进程的处理器状态。