【Linux我做主】进程优先级

进程优先级

  • 进程优先级
  • github地址
  • [0. 前言](#0. 前言)
  • [1. 优先级是什么](#1. 优先级是什么)
    • [优先级 VS 权限](#优先级 VS 权限)
  • [2. 为什么要有进程优先级](#2. 为什么要有进程优先级)
  • [3. Linux中进程的优先级](#3. Linux中进程的优先级)
    • [1. 查看进程的优先级](#1. 查看进程的优先级)
    • [2. 关键信息](#2. 关键信息)
    • [3. 进程优先级的范围和调整](#3. 进程优先级的范围和调整)
  • [4. 进程相关概念总结](#4. 进程相关概念总结)
    • 竞争性
    • 独立性
    • 并行
    • 并发
      • [0. 两个问题](#0. 两个问题)
      • [1. 进程的上下文数据](#1. 进程的上下文数据)
      • [2. 进程切换](#2. 进程切换)
      • [3. Linux中进程切换的步骤](#3. Linux中进程切换的步骤)
      • [4. 总结](#4. 总结)
  • [5. 结语](#5. 结语)

进程优先级

github地址

有梦想的电信狗

0. 前言

Linux中的PCB既可以放在多叉树中,也可以放在双向链表中,又可以放在队列或哈希表中。进程的优先级与调度有关

Linux 世界中,进程的调度如同一场没有硝烟的竞赛。每一个进程都希望抢占到更多的 CPU时间片,以便更快地完成自己的使命。而谁能先一步被调度执行,背后正是"进程优先级"在发挥着关键作用。

​ 在操作系统调度器的眼中,所有进程表面上被一视同仁,实则暗藏玄机:不同的优先级设定,决定了哪些进程能脱颖而出、率先登场。就像现实社会中有紧急任务、有普通事务,计算机系统也需要一套"轻重缓急"的调度准则,保证整体运行的效率与公平。

​ 本篇博客将从最基础的概念入手,带你深入理解 Linux 中的进程优先级设计哲学、关键参数(如 nice 值与 PRI)、调度器背后的权衡机制 ,乃至于如何通过命令行手动干预进程优先级,帮助你在系统层面更高效地掌控进程行为!


1. 优先级是什么

优先级 VS 权限

  • 优先级:对于资源的访问,优先级决定谁先访问,谁后访问。谈优先级时,代表已经有了访问资源的资格。
  • 权限:权限代表对于某种资源,有没有资格访问。

2. 为什么要有进程优先级

  • CPU只有一个,而进程有很多个。资源是有限的,进程之间是竞争关系 。多个进程之间注定会竞争CPU资源
  • 操作系统是公平的进程调度者,为了保证进程之间良性竞争CPU资源,必须给每个进程确认优先级

进程的饥饿问题:

  • 如果进程的优先级或进程调度算法设置的不合理 ,会导致某个进程长时间得不到CPU资源,该进程的代码长时间无法得到推进,就引起了该进程的饥饿问题。
    • 饥饿问题在windows下的具体表现为:某个程序卡死了无法响应。

3. Linux中进程的优先级

1. 查看进程的优先级

命令: ps -lps -al

  • ps -l 只会显示在当前bash终端下运行的进程
  • ps -al会显示在所有bash终端下运行的进程

2. 关键信息

我们很容易注意到其中的几个重要信息,有下:

  • UID : 代表执行者的身份
    • Linux中是用数字来表示用户的,也就是UIDls -n选项可以显示用户的UID
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值,表示进程优先级的修正数据
  • 注意关键数据PRINI
    • NI (nice)的存在表明Linux中进程的优先级是可以更改的,启动前启动中都可以更改。改的时候改的是NI的值

3. 进程优先级的范围和调整

范围:

我们知道优先级可以被调整!那我们可以大幅度的修改nice值,来大幅度提高我们进程的优先级,来达到让我们的进程几乎一直再被调度的目的吗?

Linux不可以!

Linux中的调度器是为了尽可能公平的调度每个进程,不想过多的让用户参与优先级的调整。

PRI and NI

  • PRI :即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
  • NI:即nice值,其表示进程可被执行的优先级的修正数值

Linux中进程的优先级的算法为:PRI(new)=PRI(old)+nicePRI值越小,该进程的优先级越高,越快被执行。

用户无法直接修改PRI的值,但可以通过修改nice值,间接修改PRI的值

  • nice值为负值的时候,该程序优先级值将变小,即其优先级会变高,越快被执行
  • 所以,调整进程优先级,在Linux下,就是调整进程nice值

Linux中的调度器是为了尽可能公平的调度每个进程,不想过多的让用户参与优先级的调整 。因此Linuxnice值设定了一个调整范围:

  • nice其取值范围是负20至19优先级一共40个等级[-20, 19]

  • Ubuntu22.04中进程的优先级初始为20,因此进程优先级的范围为0至39[0, 39]

调整:

首先:所有进程的优先级,一般不要轻易更改!

命令:

nicenice [-n NI值] 命令

  • -n NI值:给命令赋予 NI 值,该值的范围为 -20~19

例如:nice常用于在进程启动前设置其优先级

  • nice -n -5 service httpd start:该命令将service httpd starthttpd进程的nice值设置成-5,再根据计算公式可以计算出相应的优先级。

renicerenice [优先级] PID

nice 命令恰恰相反,renice 命令可以在进程运行时修改其 NI 值,从而调整优先级。此命令中使用的是进程的 PID 号,因此常与 ps 等命令配合使用


使用top命令更改进程的优先级:

  • 步骤:
  1. 切换为root用户 或使用sudo top命令提权输入top命令回车运行
  2. 进入top页面后输入r
  3. 输入要修改优先级的进程的PID
  4. 再输入要更改的nice值。

可以看到以普通用户进行修改时,权限被拒绝了。

  • 需要注意的是,Linux中进程的优先级的算法为:PRI(new)=PRI(old)+nice

  • 此处的PRI(old)是一个固定的值,Ubuntu22.04中是20CentOS 7中是80

  • 每次调整优先级时,只需要让固定值(Ubuntu22.04中是20,CentOS 7中是80)加上新的nice值,即可得到新的优先级。


4. 进程相关概念总结

竞争性

  • 系统进程数目众多 ,而CPU资源以及其他硬件只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级

独立性

  • 定义 :多个进程在运行时拥有独立的地址空间和资源,独享各种资源,多进程运行期间互不干扰的特性

并行

  • 定义 :多个进程在多个CPU或物理核心上同时执行的现象,是物理层面的真正同步运行

并发

进程并发是指在同一时间段内,多个进程被操作系统调度并交替执行的能力

  • 多个进程在一个CPU下采用进程切换 的方式,在一段时间之内,让多个进程的代码都得以推进,称之为并发执行

由于CPU运行的速度极快,即使CPU多次切换,我们运行的多个进程也不会觉得卡顿

基于进程切换基于时间片轮转的调度算法实现并发:

  • 时间段内的多任务处理
    • 并发强调在​一个时间段内​ (而非同一时刻)有多个进程处于运行状态,操作系统通过时间片轮转(Time Slicing)在进程间快速切换,使它们交替执行。
      • 例如:单核CPU上同时运行浏览器和音乐播放器,用户感知二者"同时工作",实际是CPU在毫秒级切换进程。
  • 依赖CPU调度
    Linux内核的进程调度器负责分配CPU时间片,根据优先级、状态等属性决定进程执行顺序,无需多核硬件支持。

0. 两个问题

1. 函数调用后,函数内定义的都是局部变量,return时也是局部变量,return时,为什么返回值会被外部拿到呢?

  • 外部是通过寄存器拿到函数return的数据的,具体是哪个寄存器由编译器决定

  • return ret会被翻译成mov eax, 10(假设ret的值为10 )等类似的汇编语句,通过mov指令将返回值存放在寄存器中

2. 计算机如何知道我们的进程当前执行到哪一行代码了?下一行该执行哪行代码?

  • CPU内部有一个寄存器:指令指针寄存器(PC指针) ,也被称为程序计数器或eip寄存器。
    • PC指针寄存器 :记录当前进程正在执行指令的下一行指令的地址。

CPU内部有很多寄存器,寄存器在CPU中扮演什么角色呢?

寄存器是最靠近CPU的存储器,存取数据的速度极快。将数据放入寄存器中,主要目的就是为了提高存取效率。
为了提高进程的效率,进程的一些高频数据会被放入寄存器中。

保存在CPU寄存器内部的、进程相关的临时高频数据 ,被称为进程的上下文

暂时认为进程的上下文数据被保存到了PCB中即可。但实际上因为保存到PCB中(内存级别)速度相较于太慢了,操作系统会有自己的硬件级别的做法。

1. 进程的上下文数据

定义进程的上下文数据 (Context Data)描述进程执行环境的完整状态信息 集合,用于在进程被切换出CPU时保存其运行现场,确保恢复时能继续执行。

​核心组成包括​​(按层次划分):

  • 用户级上下文:用户空间的代码段、数据段、用户栈及共享内存区域。
  • 寄存器上下文
    • 程序计数器(PC):存储下一条待执行指令地址。
    • 栈指针(SP):指向当前栈顶位置。
    • 状态寄存器(PSW/EFLAGS):记录CPU状态(如中断屏蔽位)。
    • 通用寄存器(EAX、EBX等):存储临时计算数据。
  • 系统级上下文
    • 进程控制块(PCB/task_struct):包含进程ID、优先级、资源使用等元数据。
    • 内存管理信息:页全局目录(PGD)、页表项(PTE)等虚拟地址映射数据。
    • 内核栈:内核态函数调用的栈空间。

作用上下文数据 是进程暂停和恢复的"快照",例如时间片耗尽时保存寄存器值,待重新调度时恢复现场


2. 进程切换

定义 :进程切换是操作系统在多任务环境下将CPU使用权从当前运行进程转移到另一待运行进程的过程 。其本质是上下文数据的保存与恢复,以实现进程的并发执行。

进程再从CPU上离开时,要将自己的上下文数据保存好甚至带走。保存的目的,未来都是为了恢复

​触发条件/发生情景​​:

  • 时间片耗尽(分时调度)。
  • 进程主动阻塞(如I/O请求)。
  • 高优先级进程抢占。
  • 进程结束运行。

发生进程切换时会有:

  1. 保存上下文
  2. 恢复上下文

3. Linux中进程切换的步骤

进程切换需在内核态完成,分为以下阶段:

  1. 保存当前进程上下文
    • 将CPU寄存器(PC、SP、通用寄存器等)保存到当前进程的PCB(如task_struct->thread.cpu_context)。
    • 内核栈指针等状态同步更新至PCB。
  2. 选择下一个进程
    • 调度器根据算法(如时间片轮转、优先级)从就绪队列选取目标进程。
  3. 地址空间切换
    • 更新页表基址寄存器(如ARM64的TTBR0_EL1),指向新进程的页全局目录(PGD)。
    • 清空TLB或使用ASID(地址空间标识符)避免缓存冲突。
  4. 恢复新进程上下文
    • 从新进程的PCB中加载寄存器值(PC、SP等)到CPU。
    • 切换内核栈,将执行流跳转到新进程被中断的指令地址(通过ret指令实现)。
  5. 更新运行状态
    • 新进程状态从就绪态(Ready)转为运行态(Running),旧进程可能进入阻塞或就绪队列。

4. 总结

  • 上下文数据是进程的"执行快照",包含用户/寄存器/系统级信息。
  • 进程切换是CPU使用权的转移,依赖上下文保存与恢复机制。
  • 切换步骤 的核心是地址空间更新(页表切换)和硬件状态恢复(寄存器加载)。
    这一机制使得单核CPU可通过快速切换(毫秒级)实现多进程并发执行的假象,而多核CPU可真正并行。

5. 结语

"优先级"不仅是操作系统中的一个参数,更是一种资源调配的智慧。

​ 通过本文的学习,我们了解到在多任务操作系统中,优先级机制如何协调有限资源与无限任务之间的矛盾。无论是 nice 的细致调控,还是进程切换的幕后机制,都体现了 Linux 内核"公平而高效"的设计理念。

​ 进程优先级并非洪水猛兽,也不是一成不变的设定,而是一个可以精细调整的工具。理解它、掌握它,便能更好地优化系统性能,排查卡顿问题,甚至打造属于你自己的系统调度策略。


以上就是本文的所有内容了,如果觉得文章对你有帮助,欢迎 点赞⭐收藏 支持!如有疑问或建议,请在评论区留言交流,我们一起进步

分享到此结束啦
一键三连,好运连连!

你的每一次互动,都是对作者最大的鼓励!


征程尚未结束,让我们在广阔的世界里继续前行! 🚀

相关推荐
Doris_LMS1 小时前
在Linux下安装nginx(保姆级别)
linux·运维·nginx·centos
北极糊的狐2 小时前
“我们无法设置移动热点”、网卡异常、电脑网络适配器没有2.4GHz 802.11n信道宽度和5.2GHz 802.11n信道宽度
运维·服务器
AA陈超2 小时前
虚幻引擎5 GAS开发俯视角RPG游戏 #06-11:游戏后效果执行
c++·游戏·ue5·游戏引擎·虚幻
超級二蓋茨2 小时前
在 CentOS 上安装 FFmpeg
linux·ffmpeg·centos
我爱996!3 小时前
SpringMVC——响应
java·服务器·前端
obboda4 小时前
Linux基础复习:字符输入与输出
linux·运维·服务器
*wj5 小时前
【linux驱动开发】Vscode + Remote SSH + clangd + bear=内核源码阅读环境搭建
linux·驱动开发·vscode
小学生的信奥之路5 小时前
力扣1116题:用C++实现多线程交替输出零、偶数、奇数
c++·leetcode·多线程
说私域5 小时前
从渠道渗透到圈层渗透:开源链动2+1模式、AI智能名片与S2B2C商城小程序的协同创新路径研究
人工智能·小程序·开源
Aspartame~6 小时前
企业级WEB应用服务器TOMCAT
java·运维·服务器·tomcat