第2章 进程与线程
2.1 进程和线程
2.1.1 进程的定义、组成、组织方式、特征
1.进程的定义
- 程序段、数据段、PCB(进程控制块,实现系统为每个运行的程序配置一个数据结构)构成了进程实体(进程映像),进程实体一般简称进程。
- 创建进程实质为创建PCB,撤销进程实质为撤销PCB,PCB是进程存在的唯一标志
- 进程是进程实体的运行过程(强调动态性),是系统进行资源分配和调度的一个独立单位
- 严格来说进程(动态)与进程实体(静态)并不一样,但除非特别强度动静态,否则就默认进程实体就是进程
2.进程的组成
- 程序段:程序代码
- 数据段:程序运行过程中使用产生的数据
- PCB:进程的管理者
3.进程的组织
- 组成指进程内信息,组织指进程间组织方式
- 进程组织分为链接方式(指针指向PCB队列)和索引方式(指针指向PCB索引表)
4.进程的特征
- 动态性:最基本特征
- 并发性
- 独立性:进程是资源分配、接受调度的基本单位
- 异步性
- 结构性
5.总结
2.1.2 进程的状态与转换(重点)
1.进程状态(前三个为基本状态)
- 运行态:占有CPU,几核CPU则每一时刻最多有几个进程处于运行状态
- 就绪态:拥有了除了CPU之外的所有资源,万事俱备,只欠CPU
- 阻塞态:因等待某一事件而不能运行(CPU是计算机最贵的部件,为了提高CPU利用率,进程获得其他资源后才能得到CPU的服务)
- 创建态:os分配资源、初始化PCB
- 终止态:os回收资源、撤销PCB
2.进程转换
- 补充:不能由阻塞态转为运行态的原因是进程需要先获得除CPU之外的其他资源(原因如进程状态阻塞态中的括号内容所示),转为就绪态之后才能变为阻塞态。
3.总结
2.1.3 进程控制
1.进程控制基本概念
- 定义:实现进程状态之间的转换
- 实现方式:就绪队列指针和阻塞队列指针,需要保证PCB状态标志位与所在的队列保持一致(原语实现)
2.原语
- 原语特点:执行期间不允许中断,这种不可被中断的操作称为原子操作
- 进程控制实现方式:关中断和开中断,是特权指令只能在核心态下执行,因此原语运行在核心态
- 进程控制相关原语实现的功能
- 更新PCB中的信息(修改进程状态标志、将运行环境保存至PCB,从PCB回复运行环境)
- 将PCB插入合适的队列
- 分配/回收资源
3.总结
2.1.4 进程通信
进程通信指进程之间的信息交换,各进程的内存空间相互独立,为了保证安全,一个进程不能直接访问另一个进程的地址空间,为了实现进程之间的通信,os提供了一些方法。
1.共享存储
- 内存为进程开辟共享空间,两个进程可以互斥访问
- 方式
- 基于数据结构的共享:限制数据格式,是一种低级通信方式
- 基于存储区的共享:在内存划分共享存储区,不限制数据形式,是高级通信通信方式
2.管道通信
3.消息传递
- 进程间的数据交换以格式化的消息为单位,进程间通过发送消息和接受消息两个原语进行数据交换
- 分类:
- 直接通信方式:消息直接挂到进程接收消息缓冲队列上
- 间接通信方式:消息先发送到中间实体,再被读取
4.总结
2.1.5 线程概念和多线程模式
1.线程定义
- 线程是基本的CPU执行单元,是程序流的最小单位
- 引入线程后,不仅进程间可以并发,进程内也可以并发,提高了并发度
- 引入线程后,进程只作为除CPU外的系统资源分配单元(如打印机、内存地址空间),而线程不是
2.引入线程后的变化
- 进程是资源分配、系统调度的基本单位(传统) → 进程是资源分配的基本单位,线程是系统调度的基本单位
- 只能进程间并发(传统) → 进程和线程都可并发
- 进程并发需切换进程的运行环境,系统开销大(传统) → 同一进程线程并发无需切换环境,系统开销小
3.线程属性
- 处理机调度的单位,各线程可占用不同CPU
- 每个线程都有线程ID、线程控制块(TCB),也有就绪、阻塞、运行三种基本状态
- 线程几乎不拥有系统资源,同一进程的不同线程共享进程资源,且通信无需系统干预
- 同一进程中的线程切换不会引起进程切换,不同进程的线程切换会引起进程切换;切换同进程的不同线程,系统开销小,切换进程开销大
4.线程的实现方式
- 用户级线程:线程管理由应用程序负责,在用户态下即可完成,在用户视角是多线程,从内核视角看不到线程
- 内核级线程:线程管理由操作系统内核负责,在核心态下才可完成,是从操作系统内核视角看到的线程
补:只有内核级线程才是处理机分配的单位
5.多线程模式
- 多对一模型:多个用户级线程只对应一个内核级线程
- 一对一模型:一个用户级线程对应一个内核级线程
- 多对多模型:n个用户级线程对应m个内核级线程(n大于等于m)
6.总结
2.2 处理机调度
2.2.1 处理机调度的概念、层次
1.基本概念
- 从就绪队列中按照一定的算法选择一个进程并将处理机分配给他运行,以实现进程的并发执行
2.调度三个层次
- 高级调度(作用调度)
- 中级调度(内存调度):挂起状态指的是暂时调到外寸等待的进程状态
- 低级调度(进程调度 )
- 总结
3.总结
2.2.2 进程调度的时机、方式、切换与过程
本节的进程调度即上一节的低级调度,即按照某种算法从就绪队列中选择一个进程为其分配处理机
1.进程调度的时机
- 需要进行切换
- 当前进程主动放弃:包括进程正常终止,进程运行过程中发生异常而终止,进程主要请求阻塞
- 当前进程被动放弃:包括进程时间片用完,有更紧急的事情处理,有优先级更高的进程进入就绪队列
- 不能进行切换
- 处理中断
- 进程在操作系统内核临界区(但在普通临界区中可以调度切换)
- 原子操作过程中
补:
2.调度方式
- 非剥夺调度方式(非抢占方式):只允许进程主动放弃处理机,适合于早期的批处理系统
- 剥夺调度方式(抢占方式):可以优先处理更紧急的进程,适合于分时操作系统和实时操作系统
3.进程的切换与过程
- 进程切换指的是一个进程让出处理机,由另一个进程占用处理机的过程,该过程主要完成了对原来运行进程各种数据的保存,对新的进程各种数据的恢复(一般在PCB中)
- 注意进程的切换是有代价的,频发的切换会导致效率降低
4.总结
2.2.3 调度算法的评价指标
1.CPU的利用率
-
CPU忙碌的事件占总时间的比例
-
利用率 = 忙碌事件 / 总时间
2.系统吞吐量
- 单位时间内完成作业的数量
- 系统吞吐量 = 总共完成了多少道作业 / 总共花了多长时间
3.周转时间
- (作业)周转时间 = 作业完成时间 - 作业提交时间
- 平局周转时间 = 作业周转时间之和 / 作业数
- 带权周转时间 = 作业周转时间 / 作业实际运行时间,必然大于等于1
- 平均带权周转时间 = 各作业带权周转时间之和 / 作业数
注:周转时间和带权周转时间都死越小越好
4.等待时间
- 进程等待时间:进程建立后等待被服务的时间之和,不包括被IO服务时间
- 作业等待时间:不仅考虑建立进程后的等待时间,还要加上作业在外存后辈队列中的等待时间
- 平均等待时间:进程/作业等待时间的平均值
5.响应时间
- 用户提交请求到首次产生响应所用的时间
6.总结
2.2.4 CFCS、SJF、HRRN调度算法
1.先来先服务(CFCS)
-
规则:按照作业/进程的先后顺序进行服务
-
用于作业调度时考虑的是哪个作业先到达后备队列,用于进程调度时,考虑的是哪个进程先到达就绪队列
-
属于非抢占式算法,因此只有当前作业/进程主动放弃处理机时,才需要调度
-
优点:公平、算法简单;缺点:对长作业有利,对短作业不利
-
不会导致饥饿
2.短作业优先(SJF)
- 规则:最短的作业/进程优先得到服务(每次调度时选择当前已到达且运行时间最短的作业/进程)
- 既可用于作业调度,也可用于进程调度,用于进程调度时称为“短进程优先(SPF)”
- 属于非抢占式算法,另一版本为“最短剩余时间优先算法(SRTN)”属于抢占式(每当有进程加入就绪队列改变时就需要调度,且当一个进程完成时也需要调度)
- 优点:在所有进程都几乎同时到达时,采用短作业优先算法SJF调度算法的平均等待时间、平均周转时间最少;如果不加前面条件,则最短剩余时间优先算法SRTN的平均等待时间和平均周转时间最少。缺点:对于短作业有利,对长作业不利
- 会导致饥饿
3.高响应比优先(HRRN)
- 规则:每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务(响应比 = (等待时间 + 要求服务时间) / 要求服务时间,大于等于1)
- 既可用于作业调度,也可用于进程调度
- 属于非抢占式算法
- 综合考虑了等待时间和运行时间,有CFCS和SJF的优点
- 不会导致饥饿
4.总结(这三种散发一般适用于早期的批处理系统)
2.2.5 调度算法:时间片轮转(RR)、优先级调度、多级反馈队列
1.时间片轮转(RR)
- 规则:按照进程到达就绪队列的顺序,轮流让各个进程执行一个时间片,适用于分时操作系统
- 只用于进程调度(因为只有作业放入内存建立进程后才分配时间片)
- 属于抢占式算法
- 优点:公平、响应快,适用于分时操作系统;缺点:高频的进程切换会有开销,也不区分人物的紧急程度
- 不会导致饥饿
- 如果时间片太大会退化为先来先服务,时间片太小的话会导致进程切换过于频繁
2.优先级调度算法
- 规则:每个作业/进程都有各自的优先级,调度时选择优先级最高的
- 既可以用于作业调度,也可用于进程调度
- 抢占式和非抢占式都有
- 优点:可以按照优先级进行灵活调整;缺点:可能会导致饥饿
- 根据优先级是否可以动态改变分为静态优先级和动态优先级
- 通常系统进程优先级高于用户进程;前台进程优先级高于后台进程;操作系统更偏好I/O型进程
3.多级反馈队列调度算法
- 用于进程调度
- 抢占式算法
4.总结
2.3 同步与互斥
2.3.1 进程同步、进程互斥
1.进程同步
- 同步也成为直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调他们的工作次序而产生的制约关系
2.进程互斥
- 临界资源:一个时间段内只允许一个进程使用的资源
- 对于临界资源的访问必须互斥地进行,互斥也成为间接制约关系
- 进程互斥指的是当一个进程访问某临界资源时,另一个想要访问该资源地进程必须等待。
- 对临界资源的互斥访问逻辑上可以分为进入区、临界区、退出区和剩余区,临界区是进程访问临界资源的代码,进入区和退出区是负责实现互斥的代码(上锁和解锁)
- 进程互斥的原则:空闲让进、忙则等待、有限等待、让权等待
3.总结
2.3.2 进程互斥的软件实现方法
1.单标志法
- 每个进程进入临界区的权限只能被另一个进程赋予
- 违背空闲让进原则
2.双标志先检查法
- 违反了忙则等待原则
3.双标志后检查法
- 解决了忙则等待问题,但违背了空闲让进和优先等待原则
4.Peterson算法
- 遵循了忙则等待、空闲让进、有限等待原则,违背了让权等待原则
5.总结
2.3.3 进程互斥的硬件实现方法
1.中断屏蔽方法
- 利用开关中断指令实现,与原语实现思路相同
- 优点:简单高效
- 缺点:不适合于多处理机,只适用于操作系统内核进程,不适于用户进程
2.TestAndSet指令(简称TS指令或TSL指令)
- 不同于软件的双标志先检查法和双标志后检查法,该指令可以同时进行上锁和检查
3.Swap指令
4.总结
2.3.4 信号量机制
1.定义
- 信号量为一个变量(可以为整数,也可以为复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量
- 使用wait(S)和signal(S)一对原语实现,通常wait称为P操作,signal称为V操作,所以wait(S)可以写为P(S),signal(S)可以写为V(S)
2.整型信号量
- 缺点:不满足让权等待原则
3.记录型信号量
4.总结
2.3.5 用信号量实现进程互斥、同步、前驱关系
1.信号量实现进程互斥
- 互斥信号量的初始值为1,在临界区之前执行P操作,在临界区之后进行V操作
- 对不同的临界资源需要设置不同的互斥信号量
2.信号量实现进程同步
- 进程同步目的是让各并发程序按照要求有序推进
- 设置同步信号量S,初始值为0,在前操作之后执行V操作,在后操作之前执行P操作
3.信号量实现前驱关系
- 为每一对前驱关系设置一个同步变量
4.总结
2.3.6 生产者-消费者问题
- 一对同步信号量和两对异步信号量
- 实现互斥的P操作一定要在实现同步的P操作之后,否则会出现死锁情况;两个V操作顺序可以替换
1.问题概述
2.实现方法
3.注意事项
4.总结
2.3.7 多生产者-多消费者
1.问题描述与分析
2.实现方式
3.注意事项
4.总结(从事件的前后关系考虑,而不是进程的前后关系)
2.3.8 吸烟者问题
1.问题描述与分析
2.实现方法
- 缓冲区大小为1,所以不需要互斥信号量方位缓冲区
3.总结
2.3.9 读者-写者问题
1.问题描述与分析
2.实现方法
3.总结
2.3.10 哲学家进餐问题
1.问题描述与分析
2.实现方法
3.总结
2.3.11 管程
1.管程的定义和基本特征
- 管程是一种特殊的软件模块,由共享数据结构说明,对数据结构操作的一组过程(即函数),共享数据结构的初始化语句
- 基本特征:局部于管程的数据只能被局部于管程的过程所访问;一个进程只有通过调用管程内的过程才能进入管程访问共享数据;每次仅允许一个进程在管程内执行某个内部过程
2.扩展:管程解决生产者消费者问题
3.扩展2:Java中的管程
4.总结(管程应用了封装的思想)
2.4 死锁
2.4.1 死锁的概念
1.死锁的定义
- 在并发环境下,各种进程因竞争资源而造成的一种互相等待对方手里的资源,导致各进程都阻塞无法向前推进的现象
2.死锁、饥饿、死循环
- 发生死锁的进程一定在阻塞态,且肯定不止一个进程
- 发生饥饿的进程可能在阻塞态,也可能在就绪态,可以有一个,也可以有多个
- 死锁和饥饿是操作系统的问题,死循环是程序员的问题
3.死锁产生的条件
- 互斥条件:必须对互斥使用的资源争抢,如哲学家的筷子,打印设备;而内存、扬声器可以同时让多个进程使用的资源不会导致死锁
- 不剥夺条件:进程的资源不能由其他进程强行剥夺,只能主动释放
- 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该进程又被其他资源占有
- 循环等待条件:存在进程资源循环等待链(循环等待不一定会导致死锁,死锁一定会导致循环等待)
4.死锁发生时机
- 对系统资源的竞争
- 进程顺序推进非法
- 信号量的使用不当
- 对不可剥夺资源的不合理分配可能会导致死锁
5.死锁的处理策略
- 预防死锁:破坏死锁产生的必要条件
- 避免死锁:银行家算法
- 死锁的检测和解除
6.总结
2.4.2 死锁的处理策略——预防死锁
1.破坏互斥条件
2.破坏不剥夺条件
3.破坏求和保持条件
4.破坏循环等待条件
5.总结
2.4.3 死锁的处理策略——避免死锁
1.安全序列、不安全状态、死锁
2.银行家算法
3.总结(系统处于不安全状态未必死锁,但死锁时一定处于不安全状态)
2.4.4 死锁的处理策略——死锁的检测和解除
1.死锁检测的数据结构
2.死锁检测的算法(用算法化简资源分配图后)
3.死锁的解除
4.总结