CPU Scheduling
CPU Scheduling
CPU调度程序
基本概念:
- 多道程序设计的目的将CPU 的利用率最大化。
- 多个进程同时存在于内存(并发),当一个进程暂不使用CPU时,系统调度另一 个进程占用CPU。
CPU-burst Durrations(CPU突发事件持续时间)
如图:横轴为突发时间持续时间,纵轴为发生的频率
我们将时间位于 0 - 8ms 中的进程称为 CPU-bound program 也可以被称为短进程 ,大于 8ms的进程称为 I/O-bound program 也可以被称为长进程,从频率长看大多数进程属于短进程
CPU调度程序
Whenever the CPU becomes idle(闲置), the operating system must select one of the processes in the ready queue to be executed. The selection process is carried out by the CPU scheduler.
存在两种调度方法:
- 非抢占调度(Nonpreemptive scheduling):一旦某个进程得到CPU,就会一直占用到终止或等待状态。
- 抢占调度 (preemptive scheduling):调度程序被动被动离开CPU如:时间片到期
CPU调度准则
调度算法的衡量
- CPU利用率:CPU的忙碌程度
- 响应时间:从提交任务到第一次响应的时间,针对交互式系统
- 等待时间:进程累积在就绪队列中等待的时间
- 周转时间:从提交到完成的时间
- 呑吐率:每个时钟单位处理的任务数
- 公平性:以合理的方式让各个进程共享CPU
假设作业 i 提交给系统的时刻是ts,完成的时刻是tf, 所需运行时间为 tk,那么:
单个作业的周转时间 ti:完成时间 - 开始时间
$$
ti = tf - ts
$$
平均作业周转时间 T:n为操作系统的进程数,将每个进程的周转时间累加后在平均
$$
T = \sum_{i=1}^n ti \times 1 / n
$$
调度算法
先来先服务(FCFS)
First-Come, First-Served (FCFS)
早期系统里,FCFS意味着一个程序会一直运行到结束(尽管其中会出 现等待I/O的情况)
非抢占式
如今,当一个程序阻塞时会让出CPU
假设当前就绪队列中依次存在 p1 p2 p3 p4 四个进程,p1 开始运行,运行过程中调用IO设备,此时将让出CPU进入等待状态,位于就绪队列队头的 p2 被调度器从就绪队列中取出进入运行状态,一段时间后 p1 完成IO操作要返回就绪队列,要注意的是,p1入队(从队尾入队)
第二种排列方式比第一种要好,平均周转时间缩短为18
优点:简单易行
缺点:需要控制进程先到的顺序才能时平均周转时间减少
时间片轮转(ROUND ROBIN)
时间片轮转(ROUND ROBIN)
- 每个进程都可以得到相同的CPU时间(CPU时间片, time slice),当时间片到达,进程将被剥夺CPU并加入就绪队列的尾部 。(分时系统)
- 抢占式调度算法
- n个就绪队列中的进程和时间片q:
每个进程获得1/n的CPU时间,大约是q个时间单位
没有进程等待时间会超过 (n-1)q - 例题:
等待时间分别是:
P1=(68-20)+(112-88)+(145-132)=85 P2=(20-0)+(88-40)+(132-108)=92
P3=(40-0)+(108-60)=88 dP4=(60-0)=60- 平均等待时间 = (85+92+88+60)/4=81.25
- 平均周转时间 = (153+145+112+68)/4=119.5
- RR算法分析
- 时间片(time slice)取选
- 取值太小:进程切换开销显著增大(不能小于进程切换的时间)
- 取值较大:响应速度下降(取值无穷大将退化成FCFS)
- 一般时间片的选取范围为 10ms~100ms
- 上下文切换的时间大概为 0.1ms~1ms (1%的CPU时间开销)
- RR算法优缺点
- 公平算法(+)
- 对长作业带来额外的切换开销(-)
- 时间片(time slice)取选
最短作业优先(SJF)
SJF(Shortest Job First):下一次调度总是选择所需要 CPU时间最短的那个作业(进程)。
在FCFS算法中,我们提及到,如果我们知道每个作业所需的运行时长,并按照时长从低到高的顺序依次服务,这样求出的平均周转时间是很低的,这也就是SJF算法的由来
SJF是一个非抢占式的算法,当人也可以改造为一个抢占式SRTF
以上图举例:当0时刻P1到达,1时刻 P2 到达,此时 P1 的剩余时间就变为 7 P2 剩余时间少于 P1 故优先运行 P2,依次类推直至进程全部运行完成
SJF/SRTF算法分析
- 该算法总是将短进程移到长进程之前执行,因此平均等待时间 最小,该算法被证明是最优的。
- 饥饿现象:长进程可能长时间无法获得CPU
- 该算法需要事先知道进程所需的CPU时间,预测一个进程的CPU时间并非易事
优缺点
- 优化了响应时间(+)
- 难以预测作业CPU时间(-)
- 不公平算法(-)
优先级调度(PRIORITY)
优先级通常为固定区间的数字,如[0, 10]:
- 数字大小与优先级高低的关系在不同系统中实现不一样,以 Linux为例,0为最高优先级。
- 调度策略:下一次调度总是选择优先级最高的进程。
- SJF是优先级调度的一个特例。
- 优先级调度可以是抢占式,也可以是非抢占式。
优先级的定义
- 静态优先级
- 优先级保持不变,但会出现不公平(饥饿)现象
- 动态优先级(退化Aging)
- 根据进程占用CPU时间:当进程占有CPU时间愈长,则慢慢降低它的优先级
- 根据进程等待CPU时间:当进程在就绪队列中等待时间愈长,则慢慢提升它的优先级
- 静态优先级
优先级调度(PRIORITY)
- 优先级通常为固定区间的数字,如[0, 10]:
- 数字大小与优先级高低的关系在不同系统中实现不一样,以 Linux为例,0为最高优先级。
- 调度策略:下一次调度总是选择优先级最高的进程。
- SJF是优先级调度的一个特例。
- 优先级调度可以是抢占式,也可以是非抢占式。
- 优先级的定义
- 静态优先级
- 优先级保持不变,但会出现不公平(饥饿)现象
- 动态优先级(退化Aging)
- 根据进程占用CPU时间:当进程占有CPU时间愈长,则慢慢降低它的优先级
- 根据进程等待CPU时间:当进程在就绪队列中等待时间愈长,则慢慢提升它的优先级
- 静态优先级
在linux中每个线程中存在一个控制该线程属性的结构体,
struct pthread_attr_t
,也就是pthread_create函数的第二个参数的所指值,线程属性在使用时要使用pthread_attr_init
初始化,使用完之后pthread_attr_destory
销毁- 优先级通常为固定区间的数字,如[0, 10]:
1 | int pthread_attr_init(pthread_attr_t *attr); |
线程属性其结构体为:
1 | typedef struct |
分离状态:
1 | 我们已经在前面已经知道,在默认情况下线程是非分离状态的,这种情况 |
线程的作用域:
1 | 函数pthread_attr_setscope和pthread_attr_getscope分别 |
调度策略及优先级
1 | 函数pthread_attr_setschedpolicy和pthread_attr_getschedpolicy分别用 |
调度策略可以分为两种
normal scheduling:对应的调度策略schedpolicy的取值为
SCHED_OTHER SCHED_IDLE SCHED_TATCH
,此状态下对应的优先级schedparam均为0real scheduling:对应的调度策略schedpolicy取值为
SCHED_FIFO SCHED_RR
,此状态下对应的优先级schedparam位于 1 - 99之间,数值越低意味着优先级越低我们自己创建进程的调度策略大多均为
SCHED_OTHER
模式,这种也遵循时间片轮转的策略,但要注意它位于normal,一旦由real sheduling的进程normal sheduling要让出CPU在linux终端中查看进程的优先级
方法一:
top命令,注意观察 PR 和 NI(nice)友好值
PR值越小所代表的优先级越高(与线程属性中的优先级相反),NI的取值范围(-20,19),当取值为 0 意味着这是一个普通线程,PR = 20 + NI(PR值在normal进程中范围为(0 , 39),NI值仅对normal有效),当PR值为负数或者rt)时,意味着该线程为实时线程。对于real scheduling 线程 PR = -1 - priority_value(优先级)
方法二:
chrt命令 -p + pid
1
2
3 :/mnt/c/Users/satellite$sudo chrt -p 7
pid 7's current scheduling policy: SCHED_OTHER
pid 7's current scheduling priority: 0 //优先级chrt命令也可以用来设置调度策略
参考:https://www.bilibili.com/video/BV1bf4y147PZ
https://www.jianshu.com/p/7bf93be5a1b0