进程优先级
目录
进程优先级是什么?
为什么要由进程优先级?
怎么办?
更改优先级
优先级的极值问题
进程切换
Linux真实调度算法
进程优先级是什么?
优先级是衡量得到某种资源的先后顺序,即进程得到CPU资源的先后顺序
为什么要由进程优先级?
目标资源稀缺,导致需要通过优先级确认谁先谁后的问题
权限和优先级的区别
权限是指是否能得到某种资源,优先级是能得到资源的先后问题
怎么办?
优先级也是一个数字,即int类型,存在task_struct中,值越低表明优先级越高,反之,优先级越低
我们当代Linux或其他大多数的操作系统,都是基于时间片的分时操作系统,而这一类操作系统有一个特点,必须考虑一定的公平性,虽然进程有先有后,但是差别不能过大,即优先级的数据范围不能太大,如果优先级差别过大,会导致某些优先级低的进程得到资源太晚了,因此优先级可能变化,但是变化幅度不能太大
UID
不过,本章的重点,在PRI和NI
PRI:进程优先级,默认值:80
NI:进程优先级的修正数据,nice值,默认值:0
我们说优先级可以修改,修改的就是NI值
进程真实的优先级 = PRI(默认) + NI
更改优先级
按top进入
按r进入修改
输入进程对应的pid
我们把nice值修改为10
我们就把优先级调低了
所以在code当中PRI才是真正的优先级,NI不能叫做优先级,而是叫做优先级的修正值
而当我们再想继续修改进程的nice值时,发现被拒绝了,就只能用sudo来修改了
当我们把nice值改为-10,PRI却变成了70而非90-10 = 80,因此进程真实的优先级 = PRI(默认) + NI,而默认永远都是80,Linux修改优先级,每次都是默认80,然后再做调整的
所以为什么不能调整PRI,而是只能调整NI?
因为这样我们在调整优先级的时候,不用考虑原始PRI为多少,直接按照默认80,来修改NI值即可,不必关心历史值,想改什么改什么。
其他修改nice值的命令
nice -n 5 command
上述命令以niceness值5运行command
,降低其优先级。数值越大,优先级越低
nice -n -10 command
使用负数值提高优先级(需root权限)。
renice 10 -p 1234
将PID为1234的进程niceness值改为10。
还可以用函数调用
优先级的极值问题
所以我们把nice值改为-100,我们查一下,发现NI值并没有变成-100,而是变成了-20
nice最小值为-20
我们再把nice改为+100,发现nice值变成了19
nice最大值为19
所以nice值的取值范围为[-20,19]
Linux进程的优先级范围 [60,99] 一共四十个数字
所以为什么优先级范围没有那么大呢?
因为我们已经了解到,Linux有关于修改优先级的系统调用,用户就可能通过恶意修改自己进程的优先级,来尽可能让自己的进程优先得到资源,就会让优先级低的进程,长期得不到CPU的资源,进而导致进程饥饿
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发
进程切换
1.死循环进程如何运行
a.一个进程一旦占有CPU,会把自己的代码跑完吗?
不会,除非它的代码很短,或者在一个时间片内跑完了
每一个进程系统都会分配一个时间片的东西
CPU处理一个进程只能先运行一个时间片,然后将其放入调度队列的队尾,再处理下一个进程,等到该进程再回来的时候,再接着执行。
这样就不会出现一个进程死占CPU的情况
b.死循环进程,不会打死系统,因为它不会一直占有CPU
2.CPU,寄存器
1.寄存器就是CPU内部的临时空间
2.寄存器!=寄存器里面的数据
寄存器是空间,寄存器里面的数据是内容,二者并不一样
空间只有一份,而寄存器的内容可以是变化的,多份的
3.如何切换
举一个例子,现在有政策,小明是一个大学生,小明想去当大学生兵,并成功入选了,这时小明不能直接把行李一收拾,直接就跑去当兵了,而是先要去找自己的辅导员,说明情况保留学籍,把目前小明的学习档案交给小明,让其回来后再把档案也带回来。后来,当小明当了一年兵后,回到大学继续学习,小明需要告诉辅导员自己回来了,并把自己之前的学习档案交给学校,做恢复学籍的工作
这里的学校就是CPU
导员就是调度器
小明就是进程
学籍就是进程运行的临时数据,CPU内寄存器里面的内容(当前进程的上下文数据)
保留学籍 是保留上下文数据,CPU内寄存器里面的内容,保存起来
恢复学籍 是恢复上下文数据,保存起来,恢复到CPU内的寄存器里
去当兵:进程被从CPU剥离下来
上面的过程就是完整的一次切换
在操作系统中有一个struct task_struct* current指针是在内核层面的全局指针,永远指向当前进程
也就是说当进程调度的时候,选择进程的时候就会把该进程的地址填写到该指针中,CPU在调度进程时,直接访问该指针中的地址就可以了
进程切换,最核心的,就是保存和恢复当前进程的硬件上下文数据,即CPU内寄存器的内容。
1.所以当前进程要把自己的进程硬件上下文保存起来,保存到哪里了呢?
保存到进程的 task_struct里,TSS(Task State Segment )任务状态段
2.如何区分全新的进程和已经调度过的进程
在tss中有一个标志位,标志该进程是否调度过
Linux真实调度算法
调度和切换共同构成了调度器
调度器干两件事,一调度,二选择进程
分时操作系统
实时操作系统,一旦来了一个进程,就必须立即响应,并且必须把进程一次处理完,将其处理完成后才能去处理下一个,一般在工业领域应用该系统
比如汽车制造,如果遇到危险了,需要踩刹车,刹车只能由人和系统控制,你肯定不能在汽车中装分时操作系统,前面马上撞车了,系统说不行,我的音乐还没播完,不能刹车。
实时操作系统,当我们驾驶车辆时,传感器发现要撞上了,此时操作系统直接接管,在系统内部生成实时操作系统,直接生成一个实时任务刹车,将其优先级设为最高,此时汽车就会立即执行该动作。
而在我们平常日常生活中,大多都是分时操作系统,总不至于我想玩一会电脑,电脑不让我玩,让我先写代码,那我直接不用这个操作系统了。
一般操作系统在设计时都会有实时操作系统和分时操作系统,只是有些操作系统直接把实时操作系统关掉了
下面看一下结构
从上图中,我们又引发了一个问题
如果我们链入到哈希表中的进程,优先级都很低,它又是从上到下遍历的,是不是效率又会变低呢?所以调度器如何快速的挑选一个进程呢?
可以看到queue上面还有bitmap,bitmap是什么?
bitmap是位图,以比特位来记录该位置是否有进程,它的比特位和哈希表中的slot位置是一一对应的,比特位的内容:1/0,表示是否为空,它为什么是5呢?
因为32*4 = 128 <140 无法一一对应
32*5 = 160
32*6 = 192又多了会导致资源浪费
因此就不用遍历数组了,只需要查看位图就能确定进程
可以以O(1)算法来快速确定进程
这个称为O(1)调度算法
但是这里还有问题
所以呢,仅仅这样设计,是不能满足一个卓越的优先级算法,所以runqueue又想了一个办法,又创建了一个队列
如果在运行期间,来了一个新进程,会将其放到active队列还是expired队列?
应该放到expired队列,让其处于就绪状态
而现在很多操作系统支持分时抢占
比如一个优先级60的,会直接插队,直接链入到active队列里,直接按照优先级抢占资源
其中CPU还有负载和切换次数的两个参数,就是cpu_load,nr_switch,如果有两个CPU,当新来一个进程肯定要分配给,较为闲置的那个CPU,因为这样才能平均分配资源,不能出现一个很忙的cpu,一个很闲的cpu。切换次数越多肯定越忙,负载越大肯定越忙。