【Linux】进程优先级和切换调度
目录
- 什么是优先级
- 查看和调整优先级的方法
- PRL与NI
- 查看进程优先级
- top更改nice值
- 四个小概念
- 死循环进程如何执行?
- Linux内核的调度算法
- 进程切换的本质
- 寄存器(补充知识)
- 如何切换
什么是优先级
-
问题1:如何理解权限和优先级
- 权限是这个事情能不能做,比如我们现在能不能吃饭。关注的是能还是不能,而优先级则是什么时候轮到我们吃饭,关注的是什么时候到我们吃饭,隐含了我们已经有了吃饭的权限。优先级的意义就是对于资源的访问谁先谁后(cpu资源分配的先后顺序,就是指进程的优先权)
- 权限是这个事情能不能做,比如我们现在能不能吃饭。关注的是能还是不能,而优先级则是什么时候轮到我们吃饭,关注的是什么时候到我们吃饭,隐含了我们已经有了吃饭的权限。优先级的意义就是对于资源的访问谁先谁后(cpu资源分配的先后顺序,就是指进程的优先权)
-
问题2 :为什么要有进程优先级
- 因为目标资源稀缺,需要优先级来确认先分配给谁后分配给谁。
-
问题3:操作系统是怎么做到进程优先级的?
- 操作系统采用分时间片的模式,给每个进程分配一个时间片,比如一个时间片只有10毫秒的时间,那么当CPU执行这个进程的时候呢,CPU就执行这个进程10毫秒的时间,一旦执行时间到了,那么这个进程就需要重新再运行队列里面排队等待CPU调度执行。这种模式尽量让每个进程都被执行到,防止了某个进程没被执行到导致进程饥饿的情况。
- 而进程的优先级实质上是我们task_struct(PCB)里面的一个整形数字,操作系统给每个进程分配的优先级的相差幅度不会太大,比如都是1, 3, 5,保证每个进程都有被执行。
查看和调整优先级的方法
- ps –l命令则会类似输出以下几个内容:
UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值
PRL与NI
PRI(priotity)即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
NI(nice)其表示进程可被执行的优先级的修正数值
PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
- 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行 所以,调整进程优先级,在Linux下,就是调整进程nice值
- nice其取值范围是-20至19,一共40个级别。
查看进程优先级
当我们创建一个进程后,我们可以使用ps -al命令查看该进程优先级的信息。
[cl@VM-0-15-centos pri]$ ps -al
- 注意: 在Linux操作系统中,初始进程一般优先级PRI默认为80,NI默认为0。
top更改nice值
- 进入top后按“r”–>输入进程PID–>输入nice值
- 但是注意的是:若是想将NI值调为负值,也就是将进程的优先级调高,需要使用sudo命令提升权限。
四个小概念
死循环进程如何执行?
- 这里我们前面已经提到过,CPU他执行一个进程是只执行时间片单位的时间,这个时间结束了,如果进程没有执行完,这个进程也得重新去排队,之所以这样做的效果就是为了我们前面的并发模式,达到模拟同时多进程的效果,你可以想一下,你的死循环在执行过程中,可是依然可以关掉程序执行窗口,原因就是关掉程序执行窗口也是一个进程,这就方便我们用户操作。
Linux内核的调度算法
1、需要维护两个队列让他们按顺序排队运行
- 0,99这些优先级是实时操作系统使用的优先级,我们并不关心
问题1:为什么需要维护两个队列??
- 这两个队列分别是活动队列和过期队列。在活动队列执行完后的进程就会放在过期队列相对应的位置,防止后面又来几个进程出现了插队的行为。
问题2:同等优先级的怎么办?
如图:
- queue[140]: ⼀个元素就是⼀个进程队列,相同优先级的进程按照FIFO规则进⾏排队调度,所以,
数组下标就是优先级!
问题3:为什么要有过期队列
- 如果我们一个进程被调度完后又根据优先级链接到调度队列的后面,那么这个调度队列一直有进程,一直被执行,那么后面的优先级低的调度队列就没办法执行到。这就发生了饥饿进程了。所以我们提出过期队列的概念,过期队列的进程结构和位置和活动队列进程中的结构和位置一样对应,所以交换过来并不会改变进程的优先级和同一优先级的进程位置。当活动队列为空的时候,我们交换过期队列和活动队列的指针指向(即改变active和expired指向,a->e, e->a),让过期队列变成活动队列,让活动队列变成过期队列,依次类推调用
2、需要维护一个位图,来确认位置
- 只有100-139一共40个级别,我只需要用5个字节一共40个比特位来标记是否存在进程即可,这样我们就可以通过位运算的方法快速找到 队列中存在进程的位置。 最后当位图位0的时候,就说明队列位空了!!
- 维护两个指针
- 因为当运行队列运行完之后就要让过期队列进场,所以最好的方法就是维护两个指针分别指向两个队列,然后当运行队列为空的时候再交换一下指针的指向,让等待队列变成新的运行队列
进程切换的本质
寄存器(补充知识)
- CPU里面有很多寄存器,因为CPU要处理数据,这些数据要用有一个地方临时存储起来,寄存器就可以存储这些数据,但是一定注意寄存器不是等于寄存器里面的数据,寄存器是一个空间,他不会变化,寄存器的数据是一个变量,他是可以变化的。
如何切换
- 1、你步入大学,但是你有一个参军梦,于是你报名了并且成功被选上了,你很开心于是你就直接去军营了,但是你走之前床铺没有收拾、也没有告诉学校。 于是当你在军营的时候,其实学校并不知道有你去军营了,所以他会给你安排考试,安排宿舍……结果过了一段时间当你回校后,你发现你的宿舍早就换人了,你床铺的东西也都被丢了,然后你本来应该是大一的,却显示大三,挂了三四十门课,即将被勒令退学…… 这个时候你找到了学校说:“我又不是干坏事,而是去当兵,为什么要让我退学??” 学校:“这不怪我啊,你没有打招呼,我根本就不知道你当兵去了”……
2、还是刚刚的你,但是这次你把自己的床铺收拾好了打包带走,然后你走之前去跟导员报告,将自己的入伍证明交予他查看,然后像学校请求保留学籍,其实就相当于把你的档案给封存了,这个时候学校知道你去当兵了,所以就不会给你安排考试,不会安排宿舍,你的学籍被保留了,你是大二上学期当的兵,你回来时候也是大二上学期……
通过上面两个故事,我们明白了在我们离开之前一定要做好收尾,这样才能更好地回来,所以对于进程来说,进程从CPU离开的时候,也要将自己的上下文数据保存好然后带走,保存的目的是为了更好地回来(恢复)
如图:
问题1:进程在被切换的时候要做什么
- (1) 保存上下文 (2)恢复上下文
问题2:保存在哪里?
- 存储在PCB中,PCB内部应该有相关的结构体,在寄存器要去执行其他进程之前将相关的数据先存在内部,然后寄存器就可以离开了,当后面寄存器回来的时候就可以帮助进程恢复之前的数据。