目录
[一 进程优先级](#一 进程优先级)
[1 基本概念](#1 基本概念)
[2 查看系统进程](#2 查看系统进程)
[PRI NI](#PRI NI)
[二 补充概念---竞争、独立、并行、并发](#二 补充概念---竞争、独立、并行、并发)
[三 进程切换](#三 进程切换)
[1 一个知识点](#1 一个知识点)
[2 一个故事](#2 一个故事)
[四 调度队列](#四 调度队列)
[1 Linux2.6内核进程O(1)调度队列](#1 Linux2.6内核进程O(1)调度队列)
[2 ⼀个CPU拥有⼀个runqueue(调度队列)](#2 ⼀个CPU拥有⼀个runqueue(调度队列))
[3 两个问题](#3 两个问题)
一 进程优先级
1 基本概念
优先级指的是得到某种资源的先后顺序。最常见的资源就是CPU
CPU 资源分配的先后顺序,由进程的优先权(priority)决定。
优先权高的进程拥有优先执行的权利,在多任务环境的 Linux 系统中,配置进程优先权十分实用,能够有效改善系统性能。
还可以将进程调度到指定的 CPU 上运行,将不重要的进程安排在某个专属 CPU 上,能大幅提升系统的整体性能。
为什么一个CPU一个调度队列?
因为队列的本质就是确认优先级,且CPU只有一个
2 查看系统进程
ps -l:查看当前终端下的优先级。
ps -al:查看当前所有进程的优先级。

UID
UID是用户id,表明这个进程是由谁启动的
为什么这里不用登录的用户名?
因为在Linux中,真正标识"我"这个人,是通过UID这个数字,但是人看数字不舒服,所以Linux系统会在相关配置文件把用户名和UID的关系建立起起来,打印时默认打印用户名
ls-ln:显示UID

cat /etc/passwd:查看 Linux 系统所有用户的基础账户信息

PRI NI
PRI:当前进程的优先级
NI:全称nice,属于 进程优先级的修正数据 修改了nice值,进程的优先级会改变
PRI(new) = PRI(old) + nice:PRI值越小,优先级越高
top命令修改nice值

因为操作系统不建议修改优先级,可能对程序的平衡性产生影响,所以我们在修改nice值的时候可能会受到系统阻拦,但是超级用户可以修改,所以我们用whoami查看是否为超级用户,可以使用sudo提权
当我们多次修改nice值之后发现:新的PRI值和上一次的PRI值之间没有关系,为什么呢?
因为其实PRI(old)是个常数,一般是80,所以每一次计算优先级时,都不用算上一次的优先级

我们在多次修改nice值之后发现:nice值的范围是【-20,19】 一共是四十个数字(为什么是这个数字,调度时讲),所以PRI的范围是【60,99】
二 补充概念---竞争、独立、并行、并发
-
竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
-
独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。
-
并行:多个进程在多个CPU下分别、同时进行运行,这称之为并行。
-
并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。(CPU切换的速度非常快,人感受不到)


时间片:给每个进程单位时间内在CPU上执行的时间(int counter,在OS上是整数)
三 进程切换

1 一个知识点
CPU内部是有寄存器,保存当前正在运行程序的临时数据
- 程序中的所有变量都存储在内存中,CPU 要计算数据时,需要先把变量加载到寄存器中;寄存器会保存这些待计算的临时数据,计算完成后,再通过寄存器返回计算结果。
- 进程切换的本质,就是 CPU 切换正在运行的进程。
- 寄存器保存临时数据的核心目的:为了后续恢复进程的运行状态

2 一个故事
1 大学生被征兵选上,不能直接离校走人,否则会被退学 ------ 对应:CPU 不能直接切换进程,否则当前进程的运行状态会丢失。
2 找导员申请保留学籍,导员把个人信息整理成档案交给学生 ------ 对应:CPU 将当前进程的临时数据(寄存器中的数据)保存到内存中。
3 退伍返校后,把档案交回导员,恢复学籍信息 ------ 对应:进程再次被 CPU 调度时,从内存中把保存的临时数据重新加载到寄存器,恢复进程的运行状态 。
核心逻辑:保存档案(临时数据)的目的,就是为了后续恢复学籍(进程运行状态)
结论:
寄存器!=寄存器内部的数据
寄存器是一个硬件,寄存器内部的数据是=称为当前进程的硬件上下文:CPU内部进程相关的所有寄存器的内容(内部的数据)

四 调度队列
1 Linux2.6内核进程O(1)调度队列

2 ⼀个CPU拥有⼀个runqueue(调度队列)
这个队列在Linux内核中的代码结构:
bash
struct list_head queue[MAX_PRIO];
这个队列最多有140个元素,其中每个元素都是一个LIst_head,每一个都是一个队列

【0,99】号元素是给实时操作系统用的,【100,139】是给当前进程用的,一共有40个元素:
(1)每一个数组下标,队员的就是一个优先级;每一个优先级,对应的就是一个队列。可以把不同的进程,放入不同的队列
(2)40个元素:就是优先级有四十个的原因 priority【60,99】
例如优先级60:映射到数组下标中--->priority+40
(3)可以把它理解为:在C++学到的开散列的hash表
在相同优先级的进程内部,采用FIFO调度算法
3 两个问题
(1)怎样选择进程?
从下标100开始遍历,直到遇到第一个有效的进程。所以数字下标小的进程的队列当中,就会被优先调度
结论1:调度没有直接用某个进程的具体优先级,优先级数字,决定的是进程Task_struct入队列的问题!
但是一个一个遍历效率太低了,有没有其他算法?
有的。用位图

(2)饥饿进程问题
如果优先级为60的队列一直不结束,则优先级为80队列无法得到资源--->进程饥饿问题:无法做到公平调度
为了做到公平,runqueue内部有两个140队列, 把当前CPU正在使用的队列叫做活跃队列:active queue,没有被使用的叫做过期队列:expired queue
结论:活跃队列的调度周期内,保证按照优先级调度。过期队列的存在,保证优先级低的进程,可以被调度
👉 在宏观上,所有进程都能被调度👉 微观上,优先级高的先调度!
怎么知道队列为空?
nr_active:表示当前队列有几个进程
找到进程的时间复杂度为O(1)
Swap 交换与队列状态
- Swap 交换支持
active(活跃)和expired(过期)队列,过期队列可转为活跃队列,活跃队列也可转为过期队列。 - 改变优先级 :若找到 PCB 块并修改优先级,需要将这个进程从当前队列中断开,挂载到新优先级对应的队列。
- 但直接这么做会降低效率,调度算法是 CPU 中核心算法之一,内核不允许直接操作;
- 解决方案:若在 PCB 进程控制块中修改
nice值(进而修改priority值),则延迟修改 ------ 在下一次轮转(过期队列和活跃队列交换)时,再根据新的nice值重新挂载进程。 - 这种方式称为:时间片 + 优先级轮转调度算法。
分时系统 & 实时系统
- 实时系统 :采用实时调度算法,有紧急任务时,要求立刻执行优先级更高的任务(基于优先级内核抢占)。
- 可不需要时间片;
- 实现方式:只用一个队列。
- 调度算法也被称作01 调度算法。