2.2.5_2 调度算法:时间片轮转,优先级,多级反馈队列
-
时间片轮转调度算法(RR,Round-Robin)
算法思想:公平地,轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应
算法思想:按照各个进程到达就绪队列的顺序,轮流让每个进程执行一个时间片。若进程未在一个时间片内执行完,则剥夺处理机,将进程重新放到就绪队列队尾重新排队
用于进程调度(只有作业放入内存建立相应的进程后,才能被分配处理机时间片)
是否可抢占?若进程为能在时间片内运行完,将被强行剥夺处理机使用权,因此时间片轮转调度算法属于抢占式的算法。由时钟装置发出时钟中断来通知CPU时间片已到
时间片为2:
时间片为5:
如果时间片太大,使得每个进程都可以在一个时间片完成,则时间片轮转算法退化为先来先服务调度算法,并且会增大进程相应时间。因此时间片不能太大
如果时间片太小,进程调度,切换是有时间代价的(保存,运行环境),因此如果时间片太小,会导致进程切换过于频繁,系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比例减少。因此时间片不能太小
优点:公平,响应快,适合分时操作系统
缺点:由于高频率进程切换,因此有一定的开销;不区分任务紧急程度
是否会导致饥饿?不会
-
优先级调度算法
算法思想:根据计算机的发展,特别是实时操作系统的出现,越来越多的应用场景需要根据任务的紧急程度来决定处理顺序
算法规则:每个作业/进程都有各自的优先级,调度时选择优先级最高的作业/进程
用于作业调度还是进程调度?既可用于作业调度,也可用于进程调度。甚至还会用于之后的I/O调度中
抢占式还是非抢占式?抢占式和非抢占式都有。做题时区别在于,非抢占式只需在进程主动放弃处理机时即可,而抢占式还需在就绪队列变化时,检查是否会发生抢占
根据优先级是否可以动态改变:可将优先级分为静态优先级和动态优先级两种
静态优先级:创建进程时确定,之后一直不变
动态优先级:创建进程时有一个初始值(设置初始值:系统进程优先级高于用户进程,前台进程的优先级高于后台进程,操作系统更偏好I/O型进程),之后会根据情况动态地调整优先级。
如果使用动态优先级,从追求公平,提升资源利用率等角度考虑;如果某进程在就绪队列中等待了很长时间,则可以适当提升其优先级;如果某进程占用处理机运行了很长时间,则可适当降低其优先级
优点:用优先级区分紧急程度,重要程度,适用于实时操作系统。可灵活地调整对各种作业/进程的偏好程度
缺点:若源源不断有高优先级到来,则可能导致饥饿
是否导致饥饿?会
思考:FCFS算法的特点是公平,SJF算法的优点是能尽快处理完短作业,平均等待/周转时间等参数很优秀,时间片轮转调度算法可以让各个进程得到及时的响应,优先级调度算法可以灵活地调整各种进程被服务的机会。那么能否对其他算法做个折中平衡得到一个综合表现优秀的算法呢?
-
多级反馈队列调度算法
新进程源源不断到来时,会导致之前的进程一直得不到响应引起饥饿
在多级反馈队列调度算法中,当P2被剥夺处理机使用权并重新放回第二级队列的队尾后,其剩余的时间片会被重置。因此,当P3运行完毕,P2再次获得CPU时,它将获得一个新的完整时间片(即2个时间单位),而不是继续之前被中断的剩余时间片。
2.2.5_3 多级队列调度算法
2.2.6 多处理机调度
多处理机就是多核CPU,每个CPU可以单独运行一个进程
新的问题:
2个新的目标:负载均衡(尽可能让每个CPU都同等忙碌)和处理机亲和性(尽可能让一个进程调度到同一个CPU上运行,以发挥CPU中缓存的作用(Cache))
-
公共就绪队列
所有CPU共享一个就绪进程队列,每个CPU运行调度程序时,从公共就绪队列中选择一个进程运行(每个CPU访问公共就绪队列时需要上锁,确保互斥)
图下的P1,P2…指的是各个进程的PCB,用队列的形式把他们搞一起
特点:所有CPU共享一个就绪进程队列(位于内核区)。每个CPU运行调度程序(FCFS,SJF,RR),从公共就绪队列中选择一个进程运行
-
私有就绪队列
每个CPU有一个私有的就绪进程队列。每个CPU运行时调度程序,从私有就绪队列中选择一个进程运行
私有就绪队列天然的实现了”处理机亲和性“
2.3.1 同步与互斥的基本概念
进程同步
进程具有异步性:异步是指各并发执行的进程以各自独立的,不可预知的速度前进
如何解决进程异步呢?
用进程同步解决。 进程同步也称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需在某些位置上协调他们的工作次序而产生的制约关系。进程间的直接制约关系就是源于他们之间的互相合作
进程互斥
一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备如摄像头打印机都是临界资源,此外如变量数据内存缓冲区等也属于临界资源
==对临界资源的访问,必须互斥的进行,即同一时间段内只能允许一个进程访问该资源。==互斥,亦称间接制约关系。进程互斥是指一个进程访问某临界资源时,另一个进程想访问该临界资源必须等待。当前访问临界资源的进程访问结束,释放该资源后,另一个进程才能去访问临界资源
临界区是进程中访问临界资源的代码
进入区和退出区是负责实现互斥的代码段
进程互斥的原则:
- 空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区,也就是允许一个进程访问
- 忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待
- 有限等待。对请求访问的进程,应保证能够在有限的时间内进入临界区(保证不会饥饿)
- 让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待
2.3.2_1 进程互斥的软件实现方法
-
单标志法
算法思想:两个进程在访问完临界区后会把使用临界区的权限转让交给另一个进程。也就是说每个进程进入临界区的权限只能被另一个进程
在进入区只”检查“不“上锁”,在退出区把临界区的使用权转交给另一个进程
缺点:违背“空闲让进”的原则。如果此时允许进入临界区的进程是P0,而P0一直不访问临界区,那么虽然临界区空闲,但是并不允许P1访问。
-
双标志先检查
算法思想:设置一个布尔值数组flag[],数组中各个元素用来标记各进程想进入临界区的意愿。比如"flag[0]=true"意味着0号进程P0现在想进入临界区。每个进程在进入临界区之前先检查当前有没有别的进程想进入临界区,如果没有,则把自身对应标志flag[i]设为true,之后开始访问临界区
缺点:违反了”忙则等待“的原则。图示按照152637的顺序执行,P0和P1会同时访问临界区。原因在于,进入去的”检查“和”上锁“两个处理不是一气呵成的。”检查“后,”上锁“前可能发生进程切换
-
双标志后检查
先“上锁”后检查
缺点:违背了“空闲让进”和“有限等待”的原则,会因各进程都长期无法访问临界资源而产生“饥饿”现象。若按1526的顺序执行,P0和P1都无法进入临界区
-
Peterson算法
算法思想:在进入区”主动争取-主动谦让-检查对方是否想进,己方是否谦让“
2.3.2_2 进程互斥的硬件实现方法
-
中断屏蔽方法
-
TestAndSet(简称TS指令/TSL指令)
是用硬件实现的,执行的过程不允许被中断,只能一气呵成。
//布尔型共享变量lock表示当前临界区是否被加锁 //true表示已加锁,false表示未加锁 bool TestAandSet(bool *lock){ bool old; old=*lock; //old用来存放lock,原来的值 *lock=true; //无论之前是否已加锁,都将lock设为true return old; //返回lock原来的值 }
old记录是否已被上锁,再将lock设为true,检查临界区是否已被上锁
有点:实现简单,适用于多处理机环境 -
Swap指令(XCHG指令)
用硬件实现,执行过程中不能被中断,只能一气呵成
逻辑和TSL一样
2.3.3 互斥锁
解决临界区最简单的工具就是互斥锁(mutex lock)。一个进程在进入临界区时应获得锁;在退出临界区释放锁。函数acquire()获得锁,函数release()释放锁
每个互斥锁有一个布尔变量available,表示锁是否可用。若锁是可用的,调用acqiure()会成功,且锁不再可用。当一个进程试图获取不可用的锁的时候,会被阻塞,直到锁被释放
acquire()和release()的执行必须是原子操作,因此互斥锁通常采用硬件机制来实现
缺点是忙等待。当有一个进程在临界区时,任何其他进程在进入临界区时必须连续循环调用acquire()。当多个进程共享同一CPU时,就浪费了CPU周期。因此,互斥锁通常用于多处理系统,一个线程可以在一个处理机上等待,不影响其他线程的执行
需要连续循环忙等的互斥锁,都可称为自旋锁,如TSL指令,swap指令,单标志法
特性:
- 需忙等,进程时间片用完才下处理机,违反“让权等待”
- 优点:等待期间不用切换进程上下文,多处理机系统中,若上锁时间短,则等待代价很低
- 常用于多处理机系统,一个核忙等,其他核照常工作,并快速释放临界区
- 不太适合单处理机系统,忙等的过程不可能解锁
3.4_1 信息量机制
回顾前面的进程互斥的四种软件实现方法和三种硬件实现方法,存在一些问题:在双标志检查法中,进入区的“检查”,“上锁”操作无法一气呵成,从而导致两个进程可能同时进入临界区; 所有的解决方案都无法实现“让权等待”
用户进程可以通过操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥,进程同步
信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量表示系统中某种资源的数量。比如:系统中只有一台打印机,就可以设置为一个初值为1的信号量
原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现的。
一对原语:wait(S)原语和signal(S)原语,这对原语可用于实现系统资源的“申请”和“释放”,可以把原语立即为我们自己写的函数,函数名分别为wait和signal,括号里的信号量S其实就是函数调用时传入的一个参数而已
wait,signal原语简称为P,V操作,因此做题时常把wait(S),signal(s)两个操作分别写为P(S),V(S)
-
整型信号量
用一个整数型的变量作为信号量,用来表示系统中某种资源的数量
与普通整型变量的区别:对信号量的操作只有三种,即初始化,P操作,V操作
缺点:不满足让权等待原则
-
记录型信号量
由于整型信号量忙等,因此人们又提出了”记录型信号量“,即用记录型数据结构表示的信号量
S.value的初值表示系统中某种资源的数目
S.L指向等待该资源的队列
对信号量S的一次P操作意味着进程请求一个单位的该类资源,因此需要执行S.value–,表示资源数减1,当S.value<0时表示该类资源已分配完毕,因此该进程应调用block原语进行自我阻塞(当前运行的进程从运行态—>阻塞态),主动放弃处理机,并插入该类资源的等待队列S.L中。可见,该机制遵循了“让权等待”原则,不会出现忙等
对信号量S的一次V操作意味着进程释放一个单位的该类资源,因此需要执行S.value++,表示资源数加1,若加一后仍是S.value<=0,表示仍然有进程在等待该类资源,因此应调用wakeup原语唤醒等待队列中的第一个进程(当前运行的进程从阻塞态---->就绪态)
可以用记录型信号量实现系统资源的“申请”和“释放”,实现进程互斥和进程同步
具体例子: