05 进程与线程 | 《操作系统》笔记
这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。
进程描述(静态)
- 进程的定义
- 一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程
- 进程的特点
- 动态性:可动态地创建、结束进程
- 并发性:进程可以被独立调度并占用处理机运行;并发并行
- 独立性:不同进程的工作不相互影响
- 制约性:因访问共享数据/资源或进程间同步而产生制约
- 进程的组成:进程包含了正在运行的一个程序的所有状态信息
- 程序的代码
- 程序处理的数据
- 程序计数器中的值,指示下一条将运行的指令
- 一组通用的寄存器的当前值,堆、栈
- 一组系统资源(如打开的文件)
- 进程控制块 (Process Control Block, PCB)
- 用来描述进程的数据结构,操作系统管理控制进程运行所用的信息集合
- 操作系统为每个进程都堆护了一个 PCB,用来保存与该进程有关的各种状态信息
- 操作系统用PCB来描述进程的基本情况以及运行变化的过程,PCB 是进程存在的唯一标志
- PCB 中的三大类信息
- 进程标识信息
- 本进程的标识
- 本进程的产生者标识(父进程标识)
- 用户标识
- 处理机状态信息保存区:保存进程的运行现场信息
- 用户可见寄存器:用户程序可以使用的数据,地址等寄存器。
- 控制和状态寄存器:如程序计数器 (PC),程序状态字 (PSW)。
- 栈指针:过程调用/系统调用/中断处理和返回时需要用到它
- 进程控制信息
- 调度和状态信息:用于操作系统调度进程并占用处理机使用
- 进程间通信信息:为支持进程间的与通信相关的各种标识、信号、信件等,这些信息存在接收方的进程控制块中
- 存储管理信息:包含有指向本进程映像存储空间的数据结构
- 进程所用资源:说明由进程打开、使用的系统资源,如打开的文件等
- 有关数据结构连接信息:进程可以连接到一个进程队列中,或连接到相关的其他进程的 PCB
- 进程标识信息
- PCB 的组织方式
- 链表:同一状态的进程其 PCB 成一链表,多个状态对应多个不同的链表
- 各状态的进程形成不同的链表:就绪链表、阻塞链表
- 索引表:同一状态的进程归入一个 index 表(由 index 指向 PCB),多个状态对应多个不同的 index 表
- 各状态的进行形成不同的索引表:就绪索引表、阻塞索引表
- 链表:同一状态的进程其 PCB 成一链表,多个状态对应多个不同的链表
进程状态(动态)
- 进程的生命期管理
- 进程创建
- 引起进程创建的 3 个主要事件:
- 系统初始化时
- 用户请求创建一个新进程
- 正在运行的进程执行了创建进程的系统调用
- 引起进程创建的 3 个主要事件:
- 进程运行
- 内核选择一个就绪的进程,让它占用处理机并执行
- 进程等待
- 进程只能自己阻塞自己,因为只有进程自身才能知道何时需要等待某种事件的发生
- 在以下情况下,进程等待(阻塞):
- 请求并等待系统服务,无法马上完成
- 启动某种操作,无法马上完成
- 需要的数据没有到达
- 进程唤醒
- 进程只能被别的进程或操作系统唤醒
- 进程唤醒的原因:
- 被阻塞进程需要的资源可被满足
- 被阻塞进程等待的事件到达
- 将该进程的 PCB 插入到就绪队列
- 进程结束
- 在以下四种情形下,进程结束:
- 正常退出(自愿的)
- 错误退出(自愿的)
- 致命错误(强制性的)
- 被其他进程所杀(强制性的)
- 在以下四种情形下,进程结束:
- 进程创建
- 进程状态变化模型
- 进程在生命结束前处于且仅处于三种基本状态之一,不同系统设置的进程状态数目不同
- 运行状态(Running):当一个进程正在处理机上运行时
- 就绪状态(Ready):一个进程获得了除处理机之外的一切所需资源,一旦得到处理机即可运行
- 等待状态(又称阻塞状态,Blocked):一个进程正在等待某一事件而暂停运行时,如等待某资源,等待输入/输出完成
- 进程其它的基本状态:
- 创建状态(New):一个进程正在被创建,还没被转到就绪状态之前的状态
- 结束状态(Exit):一个进程正在从系统中消失时的状态,这是因为进程结束或由于其他原因所导致
- 进程在生命结束前处于且仅处于三种基本状态之一,不同系统设置的进程状态数目不同
- 进程挂起模型:进程在挂起状态时,意昧着进程没有占用内存空间,处在挂起状态的进程映像在磁盘上
- 挂起状态
- 阻塞挂起状态(Blocked-suspend):进程在外存并等待某事件的出现
- 就绪挂起状态(Ready-suspend):进程在外存,但只要进入內存,即可运行
- 挂起把一个进程从内存转到外存,可能有以下几种情况:
- 阻塞到阻塞挂起:没有进程处于就绪状态或就绪进程要求更多内存资源时,会进行这种转换,以提交新进程或运行就绪进程
- 就绪到就绪挂起:当有高优先级阻塞(系统认为会很快就绪的)进程和低优先就绪进程时,系统会选择挂起低优先级就绪进程
- 运行到就绪挂起:对抢先式分时系统,当有高优先级阻塞挂起进程因事件岀现而进入就绪挂起时,系统可能会把运行进程转到就绪挂起状态
- 在外存时的状态转换
- 阻塞挂起到就绪挂起:当有阻塞挂起进程因相关事件岀现时,系统会把阻塞挂起进程转换为就绪挂起进程
- 解挂/激活(Activate);把一个进程从外存转到內存,可能有以下几种情况:
- 就绪挂起到就绪:没有就绪进程或挂起就绪进程优先级高于就绪进程时,会进行这种转换
- 阻塞挂起到阻塞:当一个进程释放足够内存时,系统会把一个高优先级阻塞挂起(系统认为会很快出现所等待的事件)进程转换为阻塞进程
- 状态队列
- 由操作系统来维护一组队列,用来表示系统当中所有进程的当前状态
- 不同的状态分别用不同的队列来表示(就绪队列、各种类型的阻塞队列)
- 每个进程的 PCB 都根据它的状态加入到相应的队列当中,当一个进程的状态发生变化时,它的 PCB 从一个状态队列中脱离出来,加入到另外一个队列
- 挂起状态
什么是线程
- 线程的定义
- 进程当中的一条执行流程
- 重新理解进程
- 资源管理:进程把一组相关的资源组合起来,构成了一个资源平台(环境),包括地址空间(代码段、数据段)、打开的文件等各种资源
- 线程:代码在这个资源平台上的一条执行流程
- 线程的优点
- 一个进程中可以同时存在多个线程
- 各个线程之间可以并发地执行
- 各个线程之间可以共享地址空间和文件等资源
- 线程的缺点
- 一个线程崩溃,会导致其所属进程的所有线程崩溃
- 不同操作系统对线程的支持
- MS-DOS
- 单进程单线程
- Unix
- 多进程单线程
- 现代操作系统
- 多进程多线程
- MS-DOS
- 线程与进程的比较
- 进程是资源分配单位,线程是 CPU 调度单位;
- 进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈
- 线程同样具有就绪、阻塞和执行三种基本状态,同样具有状态之间的转换关系
- 线程能减少并发执行的时间和空间开销
- 线程的创建时间比进程短,因为可以直接使用现有资源
- 线程的终止时间比进程短,因为不用销毁这些资源
- 同一进程内的线程切换时间比进程短,因为线程共享地址空间,不需要切换内存页表
- 由于同一进程的各线程间共享内存和文件资源,可直接进行不通过内核的通信
线程的实现
- 主要有三种线程的实现方式
- 用户线程:在用户空间实现,操作系统看不到
- POSIX Pthreads, Mach C-threads, Solaris threads
- 内核线程:在内核中实现
- Windows, Solaris, linux
- 轻量级进程:在内核中实现,支持用户线程
- Solaris (LightWeight Process)
- 用户线程:在用户空间实现,操作系统看不到
- 用户线程:在用户空间实现的线程机制,它不依赖于操作系统的内核,由一组用户级的线程库函数来完成线程的管理,包括进程的创建、终止、同步和调度等
- 由于用户线程的维护由相应进程来完成(通过线程库函数),不需要操作系统内核了解用户线程的存在,可用于不支持线程技术的多进程操作系统
- 每个进程都需要它自己私有的线程控制块(TCB)列表,用来跟踪记录它的各个线程的状态信息(PC、栈指针、寄存器),TCB 由线程库函数来维护
- 用户线程的切换也是由线程库函数来完成,无需用户态/核心态切换,所以速度特别快
- 允许每个进程拥有自定义的线程调度箅法
- 用户线程的缺点
- 阻塞性的系统调用如何实现?如果一个线程发起系统调用而阻塞,则整个进程在等待
- 当一个线程开始运行后,除非它主动地交出 CPU 的使用权,否则它所在的进程当中的其他线程将无法运行
- 由于时间片分配给进程,故与其它进程比,在多线程执行时,每个线程得到的时间片较少,执行会较慢
- 内核线程:是指在操作系统的内核当中实现的一种线程机制,由操作系统的内核来完成线程的创建、终止和管理
- 在支持内核线程的操作系统中,由内核来维护进程和线程的上下文信息(PCB 和 TCB)
- 线程的创建、终止和切换都是通过系统调用/内核函数的方式来进行,由内核来完成,因此系统开销较大
- 在一个进程当中,如果某个内核线程发起系统调用而被阻塞,并不会影响其他内核线程的运行
- 时间片分配给线程,多线程的进程获得更多 CPU 时间
- 轻量级进程
- 它是内核支持的用户线程,一个进程可有一个或多个轻量级进程,每个量级进程由一个单独的内核线程来支持(Solaris/Linux)。
进程控制
- 进程切换(上下文切换)
- 内容
- 暂停当前运行进程,从运行状态变成其他状态
- 调度另一个进程从就绪状态变成运行状态
- 要求
- 切换前,保存进程上下文
- 切换后,恢复进程上下文
- 快速切换(所以使用汇编实现)
- 进程生命周期的信息
- 寄存器(PC,SP,…)
- CPU 状态
- 内存地址空间
- 操作系统为活跃进程准备了进程控制块(PCB)
- 操作系统将进程控制块(PCB)放置在一个合适的队列里
- 就绪队列
- 等待 I/O 队列(每个设备的队列)
- 僵尸队列
- 内容
- 进程创建与执行
- Windows 进程创建 API: CreateProcess(filename)
- Unix 进程创建系统调用: fork/exec
- fork() 把一个进程复制成两个进程
- parent(old PID) => child(new PID)
- exec() 用新程序来重写当前进程
- PID 没有改变
- fork() 把一个进程复制成两个进程
- 用 fork 和 exec 创建进程的示例
- fork() 创建一个继承的子进程
- 复制父进程的所有变量和内存
- 复制父进程的所有 CPU 寄存器(有一个寄存器例外)
- 进程等待与退出
- wait() 系统调用是被父进程用来等待子进程的结束,配合子进程的 exit(),完成对子进程所有资源的回收
- 当子进程执行完 exit() 但是父进程还没有执行完 wait() 的这段时间,子进程处于僵尸态
- 进程结束执行之后,它调用 exit()
- 这个系统调用:
- 将这程序的“结果”作为一个参数
- 关闭所有打开的文件,连接等等
- 释放内存
- 释放大部分支持进程的操作系统结构
- 检查是否父进程是存活着的
- 如果活着,它保留结果的值直到父进程需要它;在这种情况里,进程没有真正死亡,但是它进入了僵尸(zombie/defunct)状态
- 如果没有,它释放所有的数据结构,这个进程死亡
- 清理所有等待的僵尸进程
- 进程终止是最终的垃圾收集(资源回收)
05 进程与线程 | 《操作系统》笔记