第二章
2.1 进程的概念、组成、特征
进程是程序的一次执行过程。
进程的组成:PCB(进程控制块)、程序段、数据段
PCB是进程存在的唯一标志
进程的特征
动态性;并发性;独立性;异步性;结构性
2.2进程的状态和转换
进程的状态:创建态;就绪态;运行态;阻塞态;终止态
可选状态:挂起就绪和挂起阻塞
阻塞态和挂起态
阻塞态:进程因等待某事件而暂时无法继续执行。此时进程主动放弃CPU,进入等待队列。
特征:进程仍在内存中;进程不参与CPU调度;属于同步等待,是进程主动行为。
挂起态:进程被操作系统强制移出内存,其映像保存到磁盘的交换区,以释放内存空间。挂起态分为:挂起就绪和挂起阻塞。
特征:进程不在内存中;挂起态进程不占用CPU事件;属于被动强制行为,有内存管理模块出发。
2.3 进程控制
进程控制是操作系统对进程的整个生命周期进行管理的核心功能。
进程控制是用原语实现的,原语的执行是有原子性的,即执行过程一贯到底,不允许中断。
思考:在执行一个进程指令的时候,另一个进程开始上CPU运行,如何保存当前进程的信息?
在进程切换时先在当前进程PCB中保存进程上下文运行环境(PSW、PC、通用寄存器等),当原来的进程再次运行时,通过PCB恢复运行环境。
2.4 进程间通信(IPC)
IPC指不同进程之间交换数据或信息的机制
IPC通信方式
共享内存:允许多个进程共享一块物理内存,提高数据交换效率。
分类:基于数据结构的共享;基于存储区的共享
特点:高效;进程可见;需要同步机制,防止数据竞争。
消息传递:不同进程之间以格式化消息为单位进行数据交换和同步。
分类:直接通信方式;间接通信方式
消息包含:消息头(发送进程ID、接收进程ID、消息长度等格式化消息)和消息体
使用原语:send()、receive()
管道通信:允许相关进程之间通过管道进行数据传输;管道是一个FIFO的数据流。内部实现为循环队列。
不能像共享内存一样在内存中随便写、随便读。
管道只能采用半双工通信
2.5 信号
信号:用于通知进程某个特定事件已经发生。
信号的发送和保存
进程使用系统调用kill()函数来发送信号,函数中指明进程的PID、信号类型序号。信号的发送者可以为其他进程、操作系统内核、进程自身。
信号的处理(什么时候)
如何判断是否还有需要处理的信号?
将被阻塞信号的位向量按位取反,再和待处理信号的位向量相与。
信号的处理(how)
进程自定义的信号处理程序只作用于自身进程内。
2.6 线程
线程为CPU执行和调度任务的最小单位
引入线程机制的优点:
(1)引入线程,各线程间能并发,提升并发度。
(2)同一进程内的线程切换,不需要切换进程运行环境,系统开销小。
多对一模型
特点:线程的管理工作由操作系统内核或应用程序、线程库完成,取决于线程类型:内核级线程、用户级线程;线程的切换在用户态下就可以完成;操作系统意识不到用户级线程的存在。
多对多模型
引入内核级线程:
优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行。
缺点:用户进程会占用多个内核级线程,线程切换开销大。
2.6 线程的状态与转换
线程的状态:就绪态;运行态;阻塞态
线程的组织与控制
线程切换时要保存/恢复:程序计数器;其他寄存器;堆栈指针
2.7 处理机调度
调度:操作系统从就绪队列或作业队列中选择进程或作业分配计算资源的机制
调度的三个层次:
高级调度(作业调度):按一定的原则从外存的作业后备队列中挑选一个作业调入内存,并创建进程。
低级调度(进程调度):按照某种策略从就绪队列中选取一个进程,将处理机分配给它。
中级调度(内存调度):按照某种策略决定将哪个处于挂起状态的进程重新调入内存
挂起:内存不足,将进程换出到外存
阻塞挂起->就绪挂起:事件发生,但是仍在等待操作系统调入内存执行。
2.8 进程调度时机
什么时候需要切换进程?需要进行进程调度和切换的情况
当前运行的进程主动放弃处理机:
- 进程正常终止
- 运行过程中发生异常而终止
- 进程主动请求阻塞(等待I/O)
当前运行的进程被动放弃处理机:
- 分给进程的时间片用完
- 有更紧急的事需要处理(如I/O中断)
- 有更优先级的进程进入就绪队列
进程在操作系统内核程序临界区中不能进行调度与切换
解释:内核程序临界区访问的临界资源,如果不尽快处理任务,然后释放的话,极有可能影响到操作系统内核的其他管理工作。因此在访问内核程序临界区期间不能进行调度和切换
进程处于临界区时可以进行处理机调度
解释:普通临界区访问的临界资源不会直接影响操作系统内核的管理工作。因此在访问普通临界区时可以进行调度和切换。
内核程序临界区一般用来访问某种内核数据结构的,如进程的就绪队列
进程调度的方式:
- 非剥夺调度方式(非抢占方式):只能进程终止或主动进入阻塞态
- 剥夺调度方式(抢占方式):当有更紧急的进程需要使用处理机时,则立即暂停正在执行的进程,将处理机让给更紧急的进程。
进程的调度是决策过程,从就绪队列中选择下一个要运行的进程。
进程的切换是执行过程,实际将CPU控制权从一个进程转移到另一个进程。
进程的调度、切换是有代价的。
2.9 调度器
调度时机:
- 创建新进程
- 进程退出
- 运行进程阻塞
- I/O中断发生
当没有其他就绪进程时,调度程序运行闲逛进程
闲逛进程的特性:
- 优先级最低
- 可以是0地址指令,占一个完整的指令周期
- 能耗低
2.10 调度算法
先来先服务(FCFS):按照到达的先后顺序调度
FCFS算法对长作业有利,对短作业不利。
短作业优先:最短的作业/进程优先得到服务(最短指的是要求的服务时间最短)
最短剩余时间有限算法(抢占式短作业优先算法):当有进程加入就绪队列改变时就需要调度,如果新到达的进程剩余时间比当前运行的进程剩余时间更短,则由新进程抢占处理机,当前运行进程重新回到就绪队列。
高响应比优先(HRRN):在每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务
时间片轮转调度算法(RR):按照各进程到达就绪队列的顺序,轮流让各个进程执行一个时间片。
特点:用于进程调度;抢占式算法;适用于分时操作系统
优先级调度算法:每个作业/进程有各自的优先级,调度时选择优先级最高的作业/进程
多级反馈队列调度算法:
特点:抢占式算法;进程调度;
这些算法更适合用于交互式系统
多级队列调度算法
系统会设置多个队列,当调度发生的时候选择队列,根据各队列的不同调度策略完成调度。
2.11多处理机调度
单处理机调度只需决定让哪个就绪进程优先上处理机即可。
多处理机调度不仅要调度算法让哪个就绪进程优先上处理机,还需决定被调度进程上哪个处理机。
多处理机调度
目的实现负载均衡、亲和性
(1)公有就绪队列
(2)私有就绪队列
2.12 同步互斥
进程同步:在多进程并发环境中,为了协调进程之间的执行顺序,确保它们能够按照一定的规则和次序协作完成任务,而建立的一种制约关系。
进程互斥:在多进程并发环境中,两个或两个以上的进程不能同时进入关于同一组共享变量的临界区域,否则可能发生与时间有关的错误。
临界区:进程中访问临界资源的代码段。
实现对临界资源的互斥访问,并保证系统整体性能,需满足的原则:
- 空闲让进
- 忙则等待
- 有限等待
- 让权等待
2.13进程互斥的软件实现方法
单标志法(主要是两个进程之间使用)
算法思想:使用一个标志变量来确保同一时刻只有一个进程可以进入临界区,从而实现互斥。
原理:进程间通过共享一个变量来相互协调。当一个进程想要访问临界区时会检查标志变量,标志变量表示是否有其他进程在访问临界区,如果没有,此进程可以访问临界区。
双标志先检查法
违反忙则等待原则
双标志后检查法
Peterson算法
2.15进程互斥的硬件实现方法
中断屏蔽方法:利用开关中断指令实现,在某进程开始访问临界区到结束访问为止都不允许中断
开关中断指令属于特权指令,关中断指令禁止CPU响应可屏蔽的外部中断请求,开中断指令允许CPU响应外部中断请求
TestAndSet指令
Swap指令
2.16信号量机制
用户进程可以使用操作系统提供的一对原语来对信号量进行操作,从而方便实现进程互斥和同步。
信号量表示系统中某种资源的数量。通过整数值来控制对共享资源的访问
整数型信号量
用一个整数型变量作为信号量,用来表示系统中某种资源的数量
记录性信号量
使用记录型数据结构表示的信号量
解决忙等问题
2.17信号量机制实现进程互斥
信号量机制实现进程同步
进程同步:让各并发进程按要求有序地推进
2.18生产者和消费者问题
生产者负责生成数据并将其放入缓冲区
消费者负责从缓冲区中取出数据进行处理
需解决问题:
- 互斥访问
- 同步
- 避免死锁
死锁:两个或多个进程永久阻塞,相互等待对方使用资源的释放。
实现互斥的P操作一定要在实现同步的P操作之后。
2.19读者和写者问题
漏洞:只要有一直有读进程在读,写进程就要一直阻塞等待,可能饿死,此算法中读进程是优先的。
解决方法如下:
在这种算法中不是真正的写优先,而是相对公平的先来先服务原则。称为读写公平法。
哲学家进餐问题(死锁问题)
2.20 管程
为什么要引入管程?
为了解决传统同步机制(如信号量)在编程实践中难用且易错的痛点,将并发控制复杂性从程序员手中转移给编译器和语言运行时,从而提供更高级、更安全、更易用的同步抽象。
管程
一个数据结构和能为并发进程在其上执行的一组操作。这组操作能够同步进程,并改变管程中的数据。
管程构成:管程名称;共享数据结构;操作过程;初始化代码
管程引入了条件变量
条件变量是一种特殊的变量,用于区分不同的等待原因(如缓冲区满和缓冲区空)。
条件变量可以执行两个原子操作:
wait(condition) 调用此操作的进程会释放管程的互斥锁,并进入condition的等待队列中休眠
signal(condition) 调用此操作会唤醒在condition等待队列队首的一个进程。
管程的基本特征
- 各外部进程/线程只能通过管程提供的特定入口才能访问共享数据
- 每次仅允许一个进程在管程内执行某个内部过程
2.21 死锁
死锁产生的必要条件
互斥条件:资源是独占的,即在一段时间内某资源只能被一个进程占用
请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有
不剥夺条件:进程已获得的资源。在未使用完之前,不能被其他进程强行剥夺,只能由自己主动释放
环路等待条件:存在一个由进程和资源组成的环路,环路上的每个进程都在等待下个进程所占用的资源。
如果有环外的进程持有所需资源就可打破
死锁的预防
破坏互斥条件:将临界资源改造为可共享使用的资源。例如使用打印机中的中间存储保存进程的数据,使进程不阻塞(SPOOling技术)
破坏不剥夺条件:当进程需要的资源被其他进程占有时,可通过自己或操作系统释放资源,待需要时重新申请。
破坏请求和保持条件:进程在运行前一次申请所需的全部资源,在它的资源未被满足时,不运行。
破坏循环等待条件:给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源,同类资源一次申请完。
死锁的避免
安全序列:如果系统按照这种序列分配资源,则每个进程都能顺利完成。
银行家算法
参考:王道操作系统