操作系统原理笔记–>线程与进程.____
进程切换
进程切换的实质是回收当前运行进程对 CPU 的控制权,并将 CPU 控制权转交给新调度的就绪进程.
1. 进程上下文
除进程实体之外,进程的运行还需要其他硬件环境的支持,如程序状态字 PSW、段表、页表等数据结构。一个进程运行时,CPU 所有寄存器中的内容、进程的状态以及运行栈中的内容被称为进程的上下文。进程上下文是操作系统用来管理和控制进程的内部数据集合,进程在其上下文中运行。进程上下文可分成以下三部分。
(1)系统级上下文。操作系统内核进程使用的进程上下文信息集合,主要包括 PCB 与逻辑地址到物理地址转换的核心数据结构,如段表、页表及核心栈等。
(2)寄存器上下文。CPU 中所有寄存器的信息集合,如通用寄存器、指令寄存器、程序状态字寄存器和栈指针等。栈指针可以是指向核心栈的指针,也可以是指向用户栈的指针。
(3)用户级上下文。用户进程访问和修改的进程上下文信息集合,主要包括进程的程序段、数据段、用户栈和共享存储区。用户级上下文占用进程的虚拟地址空间,交换到外存的分页或分段(内存中的信息暂存于外存,见第 4 章)仍然是进程用户级上下文的组成部分。
当内核进行进程切换时,它需要保存当前运行进程的进程上下文,以便再次执行该进程时,能够恢复到进程被切换前的运行现场和环境而继续正常运行。发生进程切换时,新、旧进程进行上下文切换。
2.进程切换的时机
进程切换是中断驱动的,引起进程切换的中断可分为以下三种。
(1)中断。中断发生时,操作系统保存当前运行进程(称为旧进程)的现场信息,调度新进程运行。
(2)异常。当 CPU 在一条指令执行时,检查到有一个或多个预定义的条件或错误产生时就会产生异常,这时,终止当前运行进程的执行,CPU 转去执行异常处理程序。
(3)系统调用。系统调用是对操作系统服务的一种显式请求。阻塞型系统调用发生时,则当前运行进程被阻塞,此时 CPU 转去执行进程调度程序。
中断发生时,操作系统暂停当前运行进程的执行,将 CPU 的执行模式切换到内核态,并通过执行进程调度程序选中一个新的就绪进程准备投入运行,这时需完成新、旧进程上下文的切换。
3.进程上下文切换
进程切换发生时,当前运行进程让出其占用的 CPU,由操作系统保存当前运行进程(旧进程)的上下文环境,并设置被进程调度程序选中的就绪进程(新进程)的上下文环境,这一过程称为进程的上下文切换。
进程的上下文环境包括中断处理可能改变的所有信息,以及恢复被中断进程运行时需要的所有信息。进程切换时,操作系统将旧进程的寄存器上下文保存到核心栈的一个上下文层。当中断返回时,由操作系统内核从核心栈中恢复,为旧进程所保存的上下文。进程切换主要包括以下 6 个步骤。
(1)当前运行进程(旧进程)被中断时,保存其 CPU 现场信息。
(2)对被中断的当前运行进程进行 PCB 更新,包括改变进程状态和其他相关信息。
(3)将被中断的当前运行进程的 PCB 移入适当的队列(因时间片到则移入进程就绪队列,因某事件发生则移入相应的进程阻塞队列)。
(4)由进程调度程序选中一个就绪进程(新进程),为其设置执行的上下文环境并对其 PCB 进行更新。
(5)修改新进程的地址空间,更新新进程的内存管理信息。
(6)恢复被选中的新进程最后一次进程上下文切换时所保存的 CPU 现场信息。
进程上下文切换时,当前运行进程(旧进程)对 CPU 的控制权被回收,其状态转变为就绪态或阻塞态。
进程调度的方式和时机
1.进程调度方式
为了实现不同的 CPU 调度目标,不同系统可以使用不同的进程调度方式。一般来说,进程的调整方式可分为非抢占式(非剥夺式)调度和抢占式(剥夺式)调度两类。
(1)非抢占式调度。在使用非抢占式调度方式的系统中,进程调度算法选中一个进程后就会让该进程一直运行下去,直到该进程运行结束自动释放 CPU 的使用权。或者在运行过程中因发生某等待事件而阻塞时,才将 CPU 的使用权返还给进程调度程序。非抢占式调度的优点是实现简单、系统开销小。但系统出现了紧急事件时不能立即处理,即实时性差。因此,非抢占式调度方式不适用于实时系统和分时系统。
(2)抢占式调度。在没有发生等待事件的情况下也允许进程调度程序暂停当前运行进程的执行,并按照某种原则将当前运行进程占用的 CPU 分配给另一个更重要、更紧迫的进程使用。在这种调度方式下,被暂停运行的进程其他所需资源均已满足而只是被剥夺了 CPU 的使用权,故其状态应由运行状态返回到就绪状态,并将其 PCB 插入到进程就绪队列。常用的抢占原则主要有以下两种。
① 高优先级原则。这种抢占原则允许拥有更高优先级的进程抢占当前运行进程所使用的 CPU。在使用高优先级抢占原则的系统中,如果有更高优先级的就绪进程到达时,则进程调度程序立即暂停当前运行进程的执行(由运行态变为就绪态),然后将 CPU 分配给这个拥有更高优先级的就绪进程使用。
② 时间片原则。在分时系统中各就绪进程按照时间片轮流执行,当运行进程的时间片到时,则进程调度程序立即暂停当前运行进程的执行(由运行态变为就绪态),然后将 CPU 分配给下一个就绪进程。
因此抢占式调度方式适合于大多数实时系统以及所有分时系统。抢占式调度能够防止一个进程较长时间占用 CPU,尤其是能够满足实时系统对响应时间的要求,且能获得较好的响应时间。但是,抢占式调度会增加系统中进程切换的频率,与非抢占式调度相比则增加了进程切换的开销。
2.进程调度的时机
进程调度程序调度性能的优劣将直接影响 CPU 的利用率,因此什么时候运行进程调度程序是操作系统处理进程调度的关键。进程调度的原则是始终使 CPU 处于忙状态,一旦 CPU 空闲就立即进行调度。引起进程调度程序运行的时机主要有两个:一个是当前运行进程执行结束而终止,或因等待某个事件的完成而无法继续执行,这时就需要启动进程调度程序来选择一个新的就绪进程投入运行;另一个是在抢占式调度系统中,进程就绪队列中出现了优先级更高的进程,或当前运行进程的时间片已经用完,这时需要剥夺当前运行进程的 CPU 使用权,并将其分配给更高优先级的就绪进程或以时间片为单位轮转的下一个就绪进程。引起进程调度的原因主要有以下 4 个。
(1)创建一个新进程后。创建一个新进程后父进程和子进程都处于就绪状态,这时需要确定是父进程先运行还是子进程先运行,即可以由进程调度程序来选择。
(2)运行进程终止。运行进程正常结束时需要向系统发出一个「进程结束」的系统调用。这时进程调度程序运行,并从进程就绪队列中选择一个新的就绪进程,然后将 CPU 分配给它。
(3)运行进程阻塞。当运行进程因发生了某种等待事件(如 I/O 请求)或阻塞在某个信号量(信号量概念见第 3 章)时,进程调度程序则调度另一个就绪进程运行。
(4)支持抢占式调度的系统中,即使没有新的就绪进程出现,为了让所有就绪进程能够轮流使用 CPU,也会在下面两种情况下引起进程调度。
① 时间片到。发现当前运行进程时间片到时引起进程调度,将 CPU 分配给下一个就绪进程。
② 进程的优先级发生变化。在按优先级调度的系统中,当进程优先级发生变化时引起进程调度。
现代操作系统在以下三种情况下不允许进行进程的调度和切换。
(1)中断处理过程中。由于中断处理通常不属于某一进程,因此不应作为进程的程序段而被剥夺 CPU。
(2)进程在操作系统内核的临界区(临界区和临界资源概念见第 3 章)中。用户进程通过陷入进入操作系统内核,为实现对临界区的互斥访问,通常以加锁方式防止其他进程进入该临界区。为了加快对临界资源的释放,在该用户进程访问临界资源期间不允许切换到其他进程去执行。
(3)在需要完全屏蔽中断的原子操作执行过程中。操作系统中常用的原子操作加锁、开锁、中断现场保护和恢复等,原子操作在执行过程中不允许进行进程切换。
3.进程调度实现
出现进程调度后,主要完成的任务是进程切换。
(1)保存当前运行进程的现场信息。当运行进程因某种原因(如时间片到或等待 I/O)需要放弃 CPU 时,进程调度程序将运行进程的 CPU 现场信息,保存到内存该进程 PCB 中的 CPU 状态保护区。
(2)选择即将运行的进程。进程调度程序根据某种调度算法从进程就绪队列中挑选一个进程,把它的状态由就绪状态改为运行状态,并准备将 CPU 分配给它。
(3)为新选中的进程恢复现场。将选中进程在内存 PCB 保存的 CPU 现场信息送入 CPU 的各寄存器,然后将 CPU 的使用权交给选中的进程,使它从上次中断运行的断点处恢复正常运行。
线程
线程可以简单地理解为 CPU 调度和执行的最小单元 线程的定义有以下 4 种不同的提法 (1)进程内的一个执行单元 (2)进程内的一个可独立调度的实体 (3)线程是进程中一个相对独立的控制流序列 (4)线程是执行的上下文 在引入线程的操作系统中,进程是资源分配的实体,而线程是进程中能够并发执行的实体,是能够被系统独立调度和分派的基本单位 线程除具有为保证其运行而必不可少的资源外,基本不拥有系统资源 一个进程可以包含若干个线程,同属于一个进程的所有线程共享该进程的全部资源。
线程的实现原理
进程在 CPU 上实现并发,而 CPU 由操作系统管理。因此进程的实现只能由操作系统内核来进行。但线程就不同了,因为线程隶属进程,除操作系统可以管理线程外,当然也可以由进程直接管理线程。因此线程存在着内核态与用户态两种实现方法。
(1)内核态线程实现。操作系统要管理线程,就要保存线程的有关资料,即将线程控制块(TCB)放在操作系统内核空间。这样,操作系统内核就同时存在进程控制块(PCB)和线程控制块(TCB)。操作系统依据 PCB 和 TCB 提供的信息对线程进行各种类似于进程的管理。操作系统管理线程最重要的优点是:编程简单,因为线程的复杂性由操作系统承担,用户在编程时无须管理线程的调度,即无须担心线程什么时候执行,什么时候阻塞;另一个优点是:如果一个线程阻塞,操作系统可以从容地调度另一个线程执行,因为在内核态下操作系统能够监控所有的线程。内核态的缺点是效率低,因为每次线程切换都要陷入到内核由操作系统来进行调度,而从用户态陷入到内核态是要花费 CPU 时间的。此外,操作系统需要维护线程表,这又要占用内核稀缺的内存资源。
(2)用户态线程实现。用户态如何进行线程调度呢?就是除正常执行任务的线程外,还需要用户自己写一个执行系统,即专门负责线程调度的线程。当运行进程因发生某个等待事件要阻塞自己并进行进程切换时先暂不切换,而是看该进程中是否还有其他线程可以执行。如果有,则将 CPU 控制权交给受阻进程中的执行系统线程,由它来调度受阻进程中另一个可执行的线程占用 CPU 运行。这种做法称为「第二次机会」,即当运行进程要阻塞时,操作系统并不切换到其他进程运行,而是给该进程第二次机会(实际上可以有多次机会)让其继续运行。如果该进程只有一个线程,或该进程的所有线程都已阻塞,这种情况下才切换到其他进程运行。用户态实现的优点是灵活,因为操作系统无须知道线程的存在,所以在任何操作系统都能应用;其次是线程切换快,因为切换仅在用户态进行而无须陷入到内核态(核心态)。用户态实现也有两个缺点:一个缺点是:需要修改操作系统,使其在进程切换时不立即切换到其他进程,而是调用受阻进程中的执行系统线程,但这个缺点因改动范围较小而并不严重;另一个严重的缺点是:操作系统在用户态下,调用受阻进程中的执行系统线程做法违反了软件应遵循的层次架构原则(上层程序调用下层服务),即这种调用是下层功能调用了上层功能(操作系统在下,执行系统线程在上)。
(3)混合式线程实现。鉴于用户态和内核态的线程实现都存在缺陷,所以现代操作系统将二者结合起来使用,称为混合式线程。用户态的执行系统线程负责进程内部线程在非阻塞时的切换;内核态的操作系统则负责阻塞线程的切换,即同时实现内核态和用户态管理。其中内核态线程较少,而用户态线程较多,每个内核态线程可以服务一个或多个用户态线程。在分配线程时,可将需要执行阻塞操作的线程设为内核态线程,而将不会执行阻塞操作的线程设为用户态线程。这样,就可以兼顾内核态和用户态的优点而避免其缺点。