Linux 进程优先级详解:调度规则与调整方法
Linux 进程优先级决定 CPU 资源分配顺序,通过 PRI 和 NI 值体现。PRI 越小优先级越高,默认初始值为 80,NI 范围 -20 到 19。可通过 ps 命令查看,使用 top 或 renice 修改进程优先级。普通用户仅能降低优先级,root 用户可提升。进程具有竞争性、独立性、并行与并发特性,系统通过优先级机制避免饥饿问题并优化整体效率。

Linux 进程优先级决定 CPU 资源分配顺序,通过 PRI 和 NI 值体现。PRI 越小优先级越高,默认初始值为 80,NI 范围 -20 到 19。可通过 ps 命令查看,使用 top 或 renice 修改进程优先级。普通用户仅能降低优先级,root 用户可提升。进程具有竞争性、独立性、并行与并发特性,系统通过优先级机制避免饥饿问题并优化整体效率。

传统链表的逻辑是:让数据结构体'依附'于链表——比如定义一个链表节点,把数据结构体作为节点的'数据域'(链表是主体,数据是附属)。

这种方式的核心问题是:数据与链表指针紧耦合,不同结构体要单独写链表逻辑,代码完全无法通用,冗余且维护成本高。
而侵入式链表正好相反:把通用链表节点'嵌入'到数据结构体内部——数据结构体是主体,链表节点是它的一个'成员'(链表逻辑通过这个嵌入的节点实现)。

侵入式链表的核心是'通用链表节点嵌入数据结构体,数据是主体,同一套链表逻辑可复用管理任意结构体,灵活且无冗余'。

(task_struct *)(start - (size_t)&((task_struct *)0)->link)->other
**1、(task_struct *)0:**将地址 0 强转为
task_struct*,虚拟结构体基址**2、(size_t)&((task_struct *)0)->link:**计算
link在结构体中的偏移量(强转size_t确保数值运算)**3、start - (size_t)&((task_struct *)0)->link:**节点地址减偏移量,得结构体起始地址
**4、(task_struct *)(...):**将结果强转回
task_struct*,最终访问other成员
用链式结构存 PCB,其实是内核'怎么方便怎么来'的选择,核心是适配进程的'动态'和内核的'资源紧':
进程是'活的',链式改起来快:进程总在创建、销毁,链式结构增删节点只动指针(一步到位),不像数组得挪一堆元素,效率差太多;
内核内存'碎',链式能凑合用:内核里难搞到大块连续内存,PCB 散着存也没事,链式靠指针串起来就行,不用纠结地址连不连续;
管理要灵活,链式好折腾:进程要切状态(比如从就绪变阻塞)、按优先级排队列,链式结构调个指针就能重组队列,比数组挪元素轻松多了;
内核代码要省事儿,链式能复用:内核里不光管 PCB,还管文件、设备这些,一套链表逻辑就能管所有这些对象,不用给每个东西写套新代码。
进程优先级是 CPU 调度进程的'先后规则':系统会给不同进程分配优先级,优先级高的进程能更优先获得 CPU 等资源的访问权(即'谁先访问、谁后访问')。
它和'权限'是不同概念:
简单说,进程优先级是'资源调度的先后顺序规则',用来让系统更高效地分配 CPU 时间。
因为资源是有限的,但进程是多个的,进程之间天然存在资源竞争关系(竞争性)。
操作系统需要通过'进程优先级'实现良性竞争:
在 Linux 或 Unix 系统中,用 ps -l 命令则会类似输出以下几个内容:

我们很容易注意到其中的几个重要信息:
PRI)在操作系统中,UID(用户标识符)是系统唯一识别用户的标识:昵称(用户名)是给人看的,可能存在重复;但 UID 是系统分配的数字编号(比如 Linux 中 root 的 UID 固定为 0),每个用户的 UID 在系统内是唯一的,不会重复。
所以系统实际是通过 UID 来区分不同用户的,而不是依赖可能重复的用户名。

从图中我们可以看到,ls 指令加上 -n 选项后,对应的文件拥有者和文件所属组的位置被 1001 这样的数字替代了,1001 就代表了当前文件拥有者的 UID 也就是用户的唯一标识符。
| 维度 | UID(用户标识符) | PID(进程标识符) |
|---|---|---|
| 核心作用 | 唯一标识用户,明确进程 / 文件的所属者 | 唯一标识进程,定位具体运行的进程实例 |
| 对应对象 | 用户(如 Linux 中 root 的 UID 固定为 0) | 进程(每个运行的程序对应至少一个 PID) |
| 唯一性范围 | 系统内用户唯一,不会重复 | 系统内进程唯一,进程结束后 PID 可复用 |
| 典型使用场景 | 1. 控制文件 / 资源的访问权限 2. 区分不同用户的进程 | 1. 操作进程(如 kill PID 终止进程)2. 查看进程状态(如 ps -p PID) |
PRI(new) = PRI(old) + nice'的规则计算(每次调整时,PRI (old) 都以默认的 80 为基准)。比如当 nice 值设为负数时,PRI 会被减小,对应的进程优先级就会升高,能更快被 CPU 执行。简单来说,在 Linux 里调整进程的优先级,本质就是调整它的 nice 值。nice 值的取值范围是 -20 到 19,共包含 40 个级别,从 -20(让进程优先级最高)到 19(让进程优先级最低),覆盖了不同场景下的调度需求。

从图中可以看到进程默认优先级是 80,也就代表了我们所能调整的最终优先级范围是 [60, 99]。
进程 nice 值与优先级调整说明
虽然进程优先级可以通过修改 nice 值调整,但不能无限制提升优先级(比如无法通过'大幅修改 nice 值'让进程一直被调度)——因为 Linux 对 nice 值的调整范围做了限制,仅允许在 [-20, 19] 区间内调整(nice 值越小,进程优先级越高)。这是系统为避免单个进程过度抢占资源、保证整体稳定性而设置的约束,不会开放过度的优先级干预权限。
启动 top:在终端输入 top,进入进程监控界面;
进入优先级调整模式:按下键盘上的 r 键(代表'renice',调整 nice 值);
输入目标进程的 PID:此时界面会提示'PID to renice:',输入要调整的进程 PID 后按回车;
输入新的 nice 值:接着提示'Renice PID [目标 PID] to value:',输入想要设置的 nice 值(范围 [-20, 19]),按回车完成调整。
【注意事项】
NI 列,看到该进程的 nice 值已更新。【修改演示】



从图中可以看到 PRI 和 NI 确实被修改了,有些同学可能疑惑:为啥查进程 PRI 和 NI 时用了 ps -la 而不是 -l 选项?这是因为 ps -l 只显示当前终端下的进程 —— 哪怕是同一用户,只要进程是在其他终端启动的,ps -l 就不会显示;而 ps -la 的 -a 参数能显示所有终端的进程,所以能稳定查到目标进程的 PRI 和 NI(图中 test 进程的 PRI、NI 已成功修改)。

如果我修改的 NI 超过可修改范围,最终的 NI 值会是多少呢?
如果修改的 NI 值超出了合法范围([-20, 19]),系统会自动按边界值生效:比如图中尝试设 NI 为 30,最终会取最大值 19;若设为 -21,则会取最小值 -20。
竞争性: 系统进程数目众多,而 CPU 资源只有少量,甚至 1 个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
▶ 比如服务器同时跑着业务程序、日志脚本、备份进程,CPU 只能轮流处理它们,优先级就是'规则'—— 让核心业务先抢到 CPU,避免卡顿。
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
▶ 每个进程都有自己的'独立空间',像你开着的浏览器和音乐播放器,浏览器崩溃不会影响音乐播放,就是独立性在隔离资源。
并行: 多个进程在多个 CPU 下分别,同时进行运行,这称之为并行。
▶ 如果服务器有 4 个 CPU 核心,进程 A、B、C、D 可以同时在 4 个核心上跑,是真正的'同时执行',能直接提升整体效率。
并发: 多个进程在一个 CPU 下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
▶ 只有 1 个 CPU 时,系统会快速切换进程(比如先跑进程 A 10ms,再切到进程 B 10ms),宏观上看这些进程像'同时在跑',但微观是 CPU 在轮流处理。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online