在开启本篇文章的学习之前,我们先要熟悉如下两个事
1.概念
进程优先级指的是进程能得到某种资源的先后顺序,要理解好它与权限的关系,优先级是 能,拥有资源的先后顺序,权限是 能还是不能的问题
2.为什么要有优先级?
因为资源是有限的,本质就是资源少进程多!!!在竞争CPU资源!Linux的优先级在task_strect里面。
3.解剖优先级
我们随便撬开一个进程:
我们会发现有几个东西:UID、PRI和NI,那这两个都是什么呢?
答案是:
UID : 代表执行者的身份
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值
3.1 PRI(Priority)
定义:PRI代表进程的优先级,决定了操作系统调度进程的顺序。PRI值越小,进程的优先级越高。
特点:PRI是一个动态值,内核会根据进程的运行状态自动调整。
取值范围:Linux系统中,PRI的取值范围是0到139。其中,0到99是实时进程的优先级范围,100到139是普通进程的优先级范围。
PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
实际上,我们上文看到的是PRI(new)值,在这里PRI(old)固定为80,我们是通过修改NI值来改变进程优先级的!!
3.2 NI(Nice值)
定义:NI是进程的静态优先级修正值,用于调整进程的优先级。通过修改nice值,可以间接改变进程的优先级。
特点:NI值是一个静态值,通常由用户手动设置,内核一般不会主动修改。
取值范围:NI值的取值范围是-20到19,一共40个级别。正值表示降低优先级,负值表示提高优先级。
3.3 总结
1)优先级范围
在Linux系统中,普通用户进程的优先级范围是60到99,一共40个级别。数值越小,表示进程的优先级越高。默认情况下,进程的优先级是80。
2)原因
这个范围限制是为了保持系统调度的公平性,防止用户随意将进程的优先级设置得过高或过低,从而避免进程饥饿问题。(这也是为什么NI值设置在【-20,19】之间的原因)
3)作用
实时进程优先:在Linux中,实时进程的优先级高于普通用户进程,因为实时进程需要即时响应,不受其他普通进程的影响。实时进程的优先级范围通常是0到99。
防止饥饿:通过限制普通进程的优先级范围,确保系统中的每个进程都有机会获得CPU资源,避免某些进程因优先级过低而长时间无法执行。
3.4 查看与修改
查看:可以通过ps -l
命令查看进程的PRI和NI值。
修改:可以使用nice
命令在启动进程时设置NI值,或者使用renice
命令动态调整正在运行的进程 的NI值。或者top命令,进入后按r,输入PID值和要更改的NI值。
4.概念补充
竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。 为了高效完成任务,更合理竞争相关资源,便具有了优先级
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰(进程之间是相互隔离的)
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
并发: 多个进程在⼀个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称
之为并发
5.进程切换

5.1 时间片
5.2 函数返回值问题
6.O(1)调度
O(1)调度算法是Linux内核中的一种进程调度算法,因时间复杂度为常数级别而得名,与进程数量无关。其核心思想是通过维护特定的数据结构,快速选择下一个要运行的进程
数据结构如下:
O(1)调度器为每个CPU维护两个队列:active
队列(存放时间片未用完的任务)和expired
队列(存放时间片已耗尽的任务)。
每个队列按优先级分为多个数组,对应不同的优先级。优先级范围为0~139,其中0~99为实时进程优先级,100~139为普通进程优先级。

我们注意到圈圈里面都有一个queue[140],bitmap[5],不同的是上面蓝色的当前是 active
队列,下面红色的是expired
队列。一个圈又是一个结构体,我们不妨定义为struct q,那这里红圈和蓝圈实际上是一个结构体数组,写为struct q array[2],蓝圈为array[0],红圈为array[1]
6.1 queue[140]
实际上,它是由结构体数组指针构成的,写作 struct tasj_struct * ,之后由链表连接而成,所以还有一个struct list_head,从0到139,总共140个,【0,99】我们先不管,先只看【60,99】,之后按优先级进行调度,这样,CPU在调度的时候只需将各个数组打开,如果里面指针为空,那就下一个,直到找到不为空的位置,但是倘如我们的进程在最后一个,139的位置,那我们的CPU岂不是还要在遍历一遍数组?实际上,不需要!这里就要看上面的那个bitmap了!
6.2 bitmap
有人可能会好奇,为什么是5而不是别的数字,实际上,这是因为我们的Int是32位,32*5=160,而32*4=128,128不够139,所以我们确定【】里面为5,而这160比特位我们称之为位图!!
6.2.1 位图
位图由一堆0和1组成,比特位位置:数组中第几个队列,比特位内容:表明该队列是否为空,为1则不为空,说明当前对应位置上挂着进程呢!
这样一来,操作系统只需要看bitmap【5】,即可确定里面那个位置有优先级最高的进程,于是便可以进行调度了!
这里在补充说明一点:CPU调度的时候,是直接从active指针,找到对应的queue[140],而我们的新增进程以及时间片到了的进程,会被从CPU上剥离下来,并重新入队列,入的是过期队列!!!
而我们的新增进程也是在这个时候会根据优先度来调度,判断出入过期队列的哪一部分的!
还有一点值得提的是,CPU调度完之后,就会跑到过期队列中,所以当我们调度完所有进程之后,所有进程都跑到过期队列中!而一但active没有进程了,那么swap(&active,&expired),交换两个指针的内容,继续调度!