1、进程的基本概念
- 程序:静态的,存在磁盘中的可执行文件,是一系列执行的集合。
- 进程:动态的,程序的一次执行过程。
- 进程的组成:PCB(进程控制块)、数据段、程序段
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/2963edd29e9adfcd0e73bfe4a3ee09b6.png)
PCB是给操作系统使用的;程序段和数据段是进程自己使用的,与进程自身的运行逻辑有关。 - 进程的特征:动态性、并发性、独立性、异步性、结构性。
2、进程的状态
2.1、进程状态的变化
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/07dabfd669074c686513a5d846852421.png)
①操作系统为进程分配资源,初始化PCB
②进程获得CPU资源,进入运行状态
③因时间片轮转或进程主动让出CPU或CPU被优先级更高的进程抢占,而进入就绪状态
④因等待某一事件而暂时不能运行或发生了系统调用(主动行为),而进行进入阻塞状态
⑤等待的事件发生或系统调用完成(被动行为),而进入就绪状态
⑥进程运行结束或发生不可修复的错误,而进入终止状态
2.2、进程的组织
- 链接方式:按照进程状态将PCB分为多个队列,操作系统持有指向各个队列的指针。
- 索引方式:根据进程状态的不同,建立多张索引表,操作系统持有指向各个索引表的指针。
2.3、进程控制
- 进程状态的转换通过原语实现,原语用关中断指令和开中断指令实现,关中断指令和开中断指令之间的指令执行完不会进行中断信号检测。原语是一种特殊的内核程序,不可中断。
- 进程状态的转换可分为三个步骤:更新PCB中的信息、将PCB插入合适的队列、分配/回收资源(不一定有)
3、进程通信(进程之间的信息交换)
3.1、进程通讯之共享存储
- 基于数据结构的共享存储:速度慢,限制多,一种低级的通讯方式
- 基于存储区的共享存储:速度快,一种高级的通讯方式
- 进程对共享空间的访问必须是互斥的(通过P/V操作)
3.2、进程通信之管道通信(缓冲区)
- 半双工通信,同一时间只能实现单向传输
- 各进程对管道的访问是互斥的
- 管道写满时,阻塞等待读操作;管道读空时,阻塞等待写操作
- 管道没写满,不允许读;管道没读空时,不允许写
3.3、管道通信之消息传递
- 直接通讯方式:消息直接挂到接收进程的消息缓冲队列上
- 间接通讯方式:消息先发送到中间实体(信箱,由操作系统维护),再由信箱分发到接收进程
- 消息传递通过发送原语和接收原语实现
4、线程
4.1、线程的基本概念
- 有些进程需要"同时"做多件事,故而需要引入线程
- 线程是一个基本的CPU执行单元
- 同一进程的不同线程间共享进程的资源
- 同一进程中的线程间通讯不需要操作系统的干预
4.2、线程的两种实现方式
用户级线程
- 通过代码逻辑实现,不是操作系统完成的,操作系统不可见,由线程库实现。
- 缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞;多个用户级线程无法在多核处理机上并发运行。
内核级线程
- 内核级线程的管理工作是由操作系统内核完成的
- 缺点:内核级线程的切换由操作系统内核完成,需要进程用户态和内核态的切换,耗费资源。
4.3、多线程模型
一对一模型
- 一个用户级线程映射到一个内核级线程,线程管理成本高
多对一模型
- 多个用户级线程映射到一个内核级线程,线程管理成本较低,当一个用户级线程被阻塞后,整个进程被阻塞,且无法在多核处理机上并发运行
多对多模型
- n个用户级线程映射到m个内核级线程(n>=m),折中方案
5、调度
5.1、三层调度
高级调度(作业调度)
- 从后备队列中选择合适的作业将其调入内存,并创建进程
- 进程状态的变化:无 -> 创建态 -> 就绪态
- 存储变化:外存 -> 内存
中级调度(内存调度)
- 从挂起队列中选择合适的进程将其数据调回内存
- 进程状态的变化:(就绪/阻塞)挂起态 -> 就绪态/阻塞态
- 存储变化:外存 -> 内存
低级调度(进程调度)
- 从就绪队列中选择一个进程为其分配CPU资源
- 进程状态变化:就绪态 -> 运行态
- 存储变化:内存 -> CPU
5.2、进程调度
- 进程调度的时机:进程正常终止、进程运行过程中发生异常、进程主动请求阻塞(I/O请求)、时间片用完、发生中断、有优先级更高的进程进入就绪队列
- 无法进行进程调度的情况:处理中断的过程中、进程处于操作系统内核程序的临界区中、在原子操作的过程中(原语)
- 进程调度的方式:非剥夺调度方式(非抢占式)、剥夺调度方式(抢占式)
5.3、调度算法评价指标
CPU利用率 = 工作时间/总时间
系统吞吐量 = 单位时间内完成作业的数量
周转时间 = 作业完成时间 - 作业提交时间
平均周转时间 = 各周转时间之和/作业数
带权周转时间 = 作业周转时间/作业实际运行时间
5.4、调度算法
| 调度算法描述 | 抢占式 | 饥饿 | 优点 | 缺点 | 适用性 |
---|
先来先服务FCFS | 先进入就绪队列先执行 | 非抢占式 | 否 | 有利于长作业和CPU繁忙性作业 | 效率低;不利于短作业和I/O繁忙型作业 | 不适用于分时系统和实时系统 |
短作业优先 | | | | | | |
先来先服务算法(FCFS)
- 特点:非抢占式、公平算法、实现简单、对长作业有利、对短作业不利、不会出现饥饿现象
短作业优先算法(SJF)
- 非抢占式:可得到最短的平均等待时间、平均周转时间,非公平算法,对短作业有利,对长作业不利,可能出现饥饿现象
- 抢占式(最短剩余时间优先算法):非公平算法,对短作业有利,对长作业不利,可能出现饥饿现象
高响应比优先算法(HRRN)
- 响应比 = (等待时间+要求服务时间)/要求服务时间
- 特点:非抢占式,只有当前运行的进程主动放弃CPU资源,才需进行调度,调度时,计算所有就绪进程的响应比,选择响应比最高的进程。
时间片轮转(RR)
- 按照各进程到达就绪队列的顺序,轮转让各个进程执行一个时间片。
- 特点:抢占式,公平算法,响应快,由于高频率的进程切换,会有一定的开销,不会出现饥饿现象
优先级调度算法
- 抢占式:当就绪队列发生改变时,需要检查是否进行抢占。
- 非抢占式:只有当前运行的进程主动放弃CPU资源,才需进行调度。
多级反馈队列调度算法
- 设置多级就绪队列,各级队列优先级从高到低,时间分从小到大
- 新进程到达时,进入第一级队列,安装先来先服务算法进行调度
- 若用完时间片进程还未结束,则进入下一级队列等待,若此时已经在最后一级队列,则放回原队列
- 只有第k级队列为空时,第k+1级队列中的进程才有机会运行
- 被抢占的进程重新放回原队列的队尾
- 可能产生饥饿现象
6、进程的同步与互斥
6.1、进程同步
- 进程具有异步性,各并发执行的进程以各自独立的,不可预知的速度向前推进,当需要进程按一定的次序推进时,就需要进程的同步机制来实现。
6.2、进程互斥
- 各并发执行的进程对部分共享资源的访问需要是互斥的。
- 临界资源的访问
进入区:检查是否可以进入临界区,若可进入,进行“上锁”
临界区:访问临界资源
退出区:负责“解锁”
剩余区:其余代码部分 - 对临界区进行访问需要遵循的原则
①空闲让进
②忙则等待
③有限等待(避免饥饿)
④让权等待(CPU资源)
6.3、进程互斥的软件实现方法
单标志法
- 两个进程在访问完临界资源后,会把临界区的使用权交给另一个进程。每个进程的使用权只能由其他进程赋予。
- 缺点:同一时刻最多只允许一个进程访问临界区;违背了“空闲让进”的原则,当p1进程使用完临界区后,将使用权交给了p2进程,但是p2进程并没有使用,此时p1进程无法再次进入临界区。
- 伪代码
int turn = 0;
{
while (turn != 0);
使用临界区资源;
trun = 1;
其余代码部分;
}
{
while (turn != 1);
使用临界区资源;
trun = 0;
其余代码部分;
}
双标志先检查法
- 设置一个布尔型数组,各元素标记各进程想进入临界区的意愿,
flag[0] = true
表示0号进程想进入临界区,每个进程进入临界区之前先检查是否有其他进程想进入临界区,没有则把自身标记设置为true,之后开始访问临界区 - 缺点:由于进入区的“检查”和“上锁”操作不是原子性的,并发运行上,可能会出现违背“忙则等待”原则的情况
- 伪代码
boolean flag[2];
while (flag[1]);
flag[0] = true;
使用临界区资源;
flag[0] = false;
剩余操作;
while (flag[0]);
flag[1] = true;
使用临界区资源;
flag[1] = false;
剩余操作;
双标志后检查法
- 设置一个布尔型数组,各元素标记各进程想进入临界区的意愿,
flag[0] = true
表示0号进程想进入临界区,每个进程进入临界区之前先把自身标记设置为true,再检查是否有其他进程想进入临界区,没有则开始访问临界区。 - 缺点:由于进入区的“检查”和“上锁”操作不是原子性的,并发运行上,可能会出现违背“空闲让进”原则和“有限等待”原则的情况
- 伪代码
boolean flag[2];
flag[0] = true;
while (flag[1]);
使用临界区资源;
flag[0] = false;
剩余操作;
flag[1] = true;
while (flag[0]);
使用临界区资源;
flag[1] = false;
剩余操作;
Peterson算法
- 结合了单标志法和双标志法的思想
- 缺点:未遵循“让权等待”的原则
- 伪代码
boolean flag[2];
int turn = 0;
flag[0] = true;
turn = 1;
while (flag[1] && turn == 1);
使用临界区资源;
flag[0] = false;
剩余操作;
flag[1] = true;
turn = 0;
while (flag[0] && turn == 0);
使用临界区资源;
flag[1] = false;
剩余操作;
6.4、进程互斥的硬件实现方法
中断屏蔽方法
- 利用关中断指令与关中断指令
- 缺点:不适用于多核处理器系统;由于关中断指令和开中断指令是特权指令,只适用于内核进程。
- 代码逻辑
关中断指令;
访问临界区资源;
开中断指令;
...
TestAndSet指令
- 简称TS、TSL指令,硬件实现,执行过程不可中断
- 缺点:未遵循“让权等待”原则
swap指令
- Exchange指令,类似TestAndSet指令,硬件实现,执行过程不可中断
7、信号量机制
- 信号量:一个变量,用于表示某种系统资源的剩余数量
- 一对原语:通过wait原语和signal原语对信号量进行操作,wait表示当前需要信号量,信号量不足则阻塞等待;signal表示释放当前进程拥有的信号量。wait与signal也简称PV操作
- 整型信号量:用一个整型变量表信号量,不遵循“让权等待”原则
- 记录型信号量:用一个数据结构表示信号量,数据结构中至少有剩余资源数和等待队列两个变量,剩余资源数为负时表示有进程处于等待队列
8、管程
1)共享数据结构
2)对共享数据结构操作的一组过程
3)对共享数据结构初始化的语句
4)管程需要一个名字
1)每次只允许一个进程在管程内执行一个过程
2)只能通过过程访问共享数据结构
9、死锁
- 在并发环境下,各进程因竞争资源而造成一种相互等待对方持有的资源,导致各进程都阻塞的现象
- 死锁的四个条件
1)互斥条件
2)不剥夺条件
3)请求和保持条件
4)循环等待条件(发生循环等待不一定产生死锁)
1)破坏互斥条件:SPOOLING技术,将互斥资源变为共享资源,局限性较大。
2)破坏不可剥夺条件:发生阻塞时,释放持有的资源
3)破坏请求和保持条件:一次性请求所有资源
4)破坏循环等待条件:使用顺序资源分配法,将资源进行编号,先申请编号小的资源
1)安全序列:系统按照一定的序列分配资源,每个进程都能顺利执行,则称这个序列为安全序列
2)核心思想:在进程提出资源请求时,先预判此次分配是否会导致系统进入不安全状态,
如果会,则暂不答应这次请求,让该进程阻塞等待
1)检测:用某种数据结构保存资源的请求和分配信息,提供一种算法,检测系统是否进入了死锁
2)解除:
a. 资源剥夺法:挂起死锁进程,并抢占它的资源
b. 终止进程法
c. 进程回退法