进程概念
- 
进程是能分配给处理器并由处理器执行的实体,由一组执行的指令、一个当前状态和一组相关系统资源所表示的活动单元,
 - 
其两个基本元素是程序代码和与代码关联的数据集。
 - 
PCB 表征进程执行的任意时刻的所有信息:
- PID:
 - State:
 - Priority
 - Program counter:
 - Memory pointers:
 - Content data:
 - I/O status info:
 - Accounting info:
 
 

进程状态
进程状态模型
两状态模型 (running or not)



五状态模型 (ready? running:blocked)


六状态模型 (add suspend)

七状态模型 (suspend read/suspend wait)



进程描述

OS控制结构

- 内存管理——内存表
 - 设备管理——I/O 表
 - 文件管理——文件表
 - 进程管理——基本进程表——进程映像
 
进程控制结构

- 进程的物理表示——进程映像:程序、数据、栈、属性集;
 

- 虚存分为内核空间和用户程序空间;
- 内核空间中为每个进程维护独特的数据结构,主要是页表、内核栈等;
 - 用户空间中可以为进程在运行时动态分配空间、有栈维护函数调用……
 
 
- OS 想要管理好进程,需要知道进程的位置和属性信息:
- 进程位置取决于内存管理方案;
 - 进程属性由 PCB 管理,分为标识信息、处理器状态信息、进程控制信息;
 - 进程控制块包含 OS 所需的进程所有信息;
 
 

进程控制块的保护问题
- 
PCB 有两个维护问题:
- 例程(如中断处理例程)中的错误可能会改变 PCB,进而破坏系统对受影响进程的管理能力;
 - PCB 结构或语义中的设计变化可能会影响到 OS 中的许多模块;
 
 - 
解决思路:
- OS 中所有例程都通过一个处理例程来解决,即处理例程的任务只是保护 PCB,且是读写 PCB 的唯一仲裁程序;
 
 
进程控制
执行模式
- 
两种执行模式:
- 与操作系统关联的处理器执行模式:特权模式(或称,控制模式、内核模式、系统模式);
 - 与用户程序关联的处理器执行模式:非特权模式;
 
 - 
处理器怎么知道正在什么模式运行?
- PSW 状态字中存在一个指示执行模式的位
 - 用户调用 OS 服务或中断进而触发系统例程执行时,置为内核模式;
 - 当系统服务返回用户进程时,置为用户模式。
 
 - 
如何设置模式?(以 IA-64 结构、Linux 系统为例)
- 处理器中 PSR (Processor Status Register)有一个 2 bit 字段 CPL,置为 0 时是最高特权级,3 是最低特权级;
 - 中断发生时,CPL 置零;
 - 中断处理程序的最后一个指令会使处理器在返回时恢复中断程序的 PSR。
 
 
进程创建
- 分配唯一的进程标识符 PID;
 - 为进程分配空间:包含进程映像中所有元素;
 - 初始化进程控制块:
- 处理进程标识 ID 和其它相关 ID(父进程 PID、用户UID);
 - 初始化处理器状态信息;
 - 初始化进程控制信息;
 - 优先级默认最低,除非显式请求;
 - 初创时不拥有任何资源;
 
 - 添加到对应状态的调度队列:将调度队列维护为链表,新进程放在就绪、就绪/挂起链表中;
 - 维护其它数据结构;
 
进程切换
- 
什么事件触发了进程切换?
- 中断
- 时钟中断
 - IO 中断
 - 内存失效——缺页中断
 
 - 陷阱
- 运算除 0
 - 用户设置的异常检查
 
 - 系统调用
- IO 请求
 
 
 - 中断
 - 
模式切换和进程切换有什么区别?
- 模式切换指的是处理器运行指令的权限是否在用户态和内核态切换;
- 模式切换可在不改变运行态进程的状态时出现,此时保存上下文及恢复的开销很小;
 
 - 进程切换指当前进程是否运行结束、时间片耗尽等,需要下一个就绪态进程占据 CPU。
 
 - 模式切换指的是处理器运行指令的权限是否在用户态和内核态切换;
 - 
保存的上下文有什么?
- 中断处理程序可能改变的所有信息,如 PSW;
 - 恢复被中断程序时需要的所有信息,如 PC;
 
 - 
==保存和恢复上下文都由硬件实现==
 - 
出现中断时,处理器会进行什么工作?——模式切换
- PC 置于中断处理程序开始处;
 - 用户模式切换到内核模式,以便中断处理代码直接运行特权指令
 - 处理器处于中断处理程序第一条指令的取指阶段,在此之前保存被中断进程的上下文到其 PCB 中
 
 
完整的进程切换步骤
- 保存处理器上下文;
 - 更新当前处于运行态进程的进程控制块,包括进程状态、退出运行态原因、记账信息等;
 - 将该进程的 PCB 移动到相应队列(就绪、阻塞、就绪/挂起);
 - 选择另一个就绪态进程开始执行,更新对应 PCB,如运行状态信息;
 - 更新内存管理数据结构,取决于管理地址转换的方式;
 - 载入 PC 和其它寄存器先前的值,恢复上下文到切换前;
 
要实现进程切换,操作系统对控制的数据结构做什么改动? 上一问题的 2、3、4、5
OS 执行的设计方法
- OS 与普通计算机软件同样运行在处理器上,也是一个程序;
 - OS 会频繁地释放控制权,并依赖于处理器来恢复控制权;
 
无进程内核
内核在所有进程的外部执行,二者分离,如图 a
- 
运行中进程遇到中断或 syscall,会保存上下文并转移控制权到内核;
 - 
OS 本身具有控制过程调用和返回的内存区域与系统栈;
 - 
OS 可以执行任何预期的功能,并恢复被中断进程的上下文,恢复中断用户进程的执行;
 - 
OS 也可以保存进程的模式上下文,并继续调度和分派另一个进程,这取决于中断的原因和当前的情况;
 - 
此方案中,进程只适用于用户程序,OS 代码是在特权模式下单独运行的实体。
 
在用户进程内执行

- 
在用户进程的上下文中执行所有 OS 软件,此时 OS 是用户调用的一组例程,在用户进程的环境内执行并实现各种功能,如图 b
 - 
任何时刻 OS 都管理着 n 个进程映像,这里的进程映像包括内核程序的代码、数据、栈区域:
 

- 
发生中断、陷阱或系统调用时,
- 该方案中处理器置于内核模式,控制权交给 OS,此前保存了模式上下文,并切换到 OS 例程。
 - 注意,此时仍然处于当前用户进程内,只是切换了模式,而不是切换了进程。
 - OS 执行完操作后,切换模式以在当前进程内恢复中断前的流程。
 
 - 
该方案最大的优点是,
- ==不论中断还是恢复,都不会产生进程切换的巨大开销==。如要进行进程切换,则要调用进程切换例程作专门处理。
 
 
基于进程的 OS

- 
第三种方案是将 OS 作为一组系统例程实现,内核功能被组织成独立的进程,如图 c
 - 
优点:
- ==鼓励使用模块化 OS 的程序设计原理,精简了模块间接口==;
 - 对非关键 OS 功能使用独立进程实现,比如用以提供资源利用率的监视,因而适合微内核结构;
 - 最后在多处理器和分布式环境中性能较好。
 
 
Unix SVR4 的进程管理
进程状态转换(9 状态)

进程创建 fork
- 
fork 请求发出时,系统执行如下操作(所有操作都在父进程的内核模式下完成):
- 在进程表中为新进程分配一个空项;
 - 为子进程分配一个唯一进程标识符;
 - 复制父进程的进程映像,但共享内存除外;
 - 增加父进程所拥有文件的计数器,反应另一个进程也拥有这些文件的事实;
 - 将子进程置为就绪态;
 - 将子进程的 ID 返回给父进程,将 0 值 返回给子进程;
 
 - 
接下来内核可以选择的去向是(三选一):
- ==停留在父进程中==,控制权返回到用户模式下父进程调用 fork 的位置;
 - ==处理器控制权交给子进程==,子进程开始执行,执行点与父进程相同,都是 fork 调用开始处;
 - ==控制权转交给另一个进程==,原父进程、子进程都处于就绪态;
 
 
线程
- 
引入线程前,进程拥有资源所有、调度执行之权:
- 资源所有权:对存放进程映像的虚拟地址空间有控制、所有权;
 - 调度执行权:多进程的执行过程会交替进行,进程是被操作系统调度和分派的实体
 
 - 
引入线程,就是为了拆分调度执行权,更加细分地利用进程申请的资源,提高效率。
 
单线程 vs. 多线程

- 
多线程环境中,进程成为了资源分配单元和保护单元,其包括:
- 容纳进程映像的虚拟地址空间;
 - 对处理器、其它进程、文件和 IO 资源的受保护访问;
 
 - 
进程中包含若干线程,每个线程包括:
- 线程运行状态;(TCB)
 - 未运行时保存的线程上下文,线程视为进程内运行的独立程序计数器;
 - 一个执行栈;
 - 每个线程用于保存局部变量的静态存储空间;
 - 与进程内其它线程共享的内存和资源访问;
 
 

- 
线程优点:
- 在已有进程中创建一个新线程的时间,远少于创建一个全新进程的时间;
 - 终止线程花费时间更少;
 - 同一进程内切换线程时间,比切换进程少得多;
 - 提高了不同执行程序间通信的效率,==同一进程间多个线程共享内存和文件,无须调用内核就可以互相通信==。
 
 - 
单用户多处理器系统中使用线程的例子:
- 前台与后台工作:如程序在前一条命令完成前提示输入下一条命令;
 - 异步处理
 - 模块化程序结构
 - 使 IO 与处理器并行
 
 
线程功能
线程状态
- 
线程执行状态:
- 运行态
 - 就绪态
 - 阻塞态
 
 - 
与线程状态改变相关的基本操作:
- 派生:新线程有自己的寄存器上下文和栈空间;
 - 阻塞
 - 解除阻塞
 - 结束
 
 
一个线程被阻塞,是否会导致整个进程被阻塞?——后文 ULT 与 KLT 会作解释。
线程同步
- 同一进程内的线程共享资源,因此需要同步线程的活动,以便互不干扰且不破坏数据结构。
 
线程分类
用户级线程

- 方案描述:
- 管理线程的所有工作都由用户空间的应用程序完成,==线程对内核透明==;
 - 线程库是管理 ULT 的例程包,提供创建销毁线程、线程通信、线程调度、线程保存与恢复上下文的功能;
 - 应用程序通常以单个线程开始,后续其它线程通过调用线程库派生获得;
 
 

- 
ULT 的优点:
- 所有线程管理数据结构都在一个进程的用户地址空间中,切换线程不需要内核模式特权,==节省了两次模式切换的开销==;
 - 线程调度策略==可以根据用户程序需要量身定做==,而不必扰乱底层 OS 的调度程序;
 - ULT ==由高级编程语言直接提供的线程库进行操控==,可移植性强,也不必对底层内核进行修改;
 
 - 
ULT 的缺点:
- ==一个线程发生阻塞时,会同时阻塞进程中其它所有线程==(如上图 b)
 - 多线程应用==无法利用多处理器技术的性能==,一个进程中只有一个线程可以获取处理器,即便在进程内实现多道程序设计;
 
 - 
解决方案:
- (不可取)将应用程序由多线程改写为多进程;
 - 套管 jacketing,将产生阻塞的系统调用转化为一个非阻塞的系统调用。
- 如,替代直接调用系统级 IO 的例程,而是调用应用级 IO 套管例程,该例程检查 IO 设备是否忙,若忙阻塞请求线程并把控制权转移;
 
 
 
内核级线程

- 
方案描述:
- ==应用级没有线程管理代码==,只有内核线程开放的 API;
 - 内核为进程及其每个线程维护上下文,==调度由内核基于线程完成==;
 
 - 
KLT 如何克服 ULT 的缺点?
- KLT 中内核可以将同一进程的==多个线程调度到多个处理器==中,
 - 并且进程的的一个线程阻塞时,可以调度其它线程运行;
 
 - 
KLT 的缺点:
- 线程切换也要涉及内核特权级的切换,模式切换会带来巨大开销;
 
 
混合 ULT 与 KLT

- 线程创建、调度、同步都在用户空间进行,只是将需要系统调用的 ULT 映射到 KLT 上;
 - 同一应用程序中的多个线程可在多个处理器上并行执行;
 
进程与线程间数量关系

多核与多线程性能
- Amdahl 定律:
 
表示可并行的代码占比。

- 即使很小的串行代码比,也会显著降低多核处理器下的性能表现;
 - 处理器越多,耗费在调度、通信、缓存上的开销就越多,性能反而下降;