当前位置: 首页 > news >正文

Linux操作系统:进程的切换与调度

进程优先级

优先级概念

CPU资源稀缺。进程优先级是操作系统调度资源的重要依据,决定了多个进程竞争CPU时的执行顺序。高优先级进程通常能更快获得CPU资源,低优先级进程则可能被延迟处理。其核心作用体现在以下几个方面:

  • 资源分配效率
    操作系统通过优先级动态调整CPU时间片的分配。例如,实时任务(如视频解码)需要高优先级以确保流畅性,而后台任务(如日志记录)可设为低优先级,避免抢占关键资源。

  • 系统响应性

    交互式应用(如用户界面)通常被赋予较高优先级,确保用户操作得到即时响应。低优先级任务(如批量数据处理)则会在系统空闲时执行,减少对用户体验的影响。
  • 负载均衡

    在多任务环境中,优先级机制帮助平衡系统负载。突发的高优先级任务(如硬件中断)可临时抢占资源,处理完成后恢复正常调度,避免资源长期被单一进程独占。

PRI和NI

在Linux命令行输入ps -l命令会显示:

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

  • UID:代表执行者的身份
  • PID:代表这个进程的代号
  • PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI:代表这个进程可被执行的优先级,其值越小越早被执行
  • NI:代表这个进程的nice值(nice取值范围:-20 ~ 19)

PRI和NI的关系是:PRI(new)= PRI(old)+ nice。所以,在Linux系统下,调整进程的优先级,就是调整进程的nice值。

注意:

  • 响到进程的优先级变化。进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程优先级的变化
  • 可以理解nice是进程优先级的修正数据。

查看进程优先级

使用ps -l命令可以查看当前用户的进程及其优先级(NI 列表示 nice 值)。例如:

ps -l

启动时设置优先级

通过nice命令启动新进程时直接指定优先级。优先级范围为 -20(最高)到 19(最低),普通用户只能调低优先级(即设置正值)。例如以优先级 10 运行命令:

nice -n 10 command

修改运行中进程的优先级

使用renice命令调整已运行进程的优先级。需指定进程 ID(PID)和目标优先级。例如将 PID 为 1234 的进程优先级改为 5:

renice -n 5 -p 1234

注意事项

  • 只有 root 用户可设置负优先级(提高优先级)。
  • 普通用户仅能调低自身进程的优先级。
  • 优先级数值越大,进程获得的 CPU 时间越少。

进程的特性和时间片解释

进程的特性

  • 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
  • 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
  • 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

什么是时间片

在操作系统中,总会有多个进程等待被CPU调度,这就是并发。每一个进程在调度队列里如果都想被轮到被CPU调度的话,那么每一个进程都会在CPU中以单位时间运行,过了时间就轮到下一个进程被调度,自己则回到队列末尾接着等待被调度。我们称这个单位时间时间片

分时操作系统:按照进程的时间片快速轮转的调度进程,可以达到人类感官上几近“同时”完成多个任务。

进程的切换

在上面我们谈到了什么是时间片,因为有了时间片的约束,才让进程得以并发执行。那么当一个进程的时间片用完,这个老进程就会从CPU身上剥离下来,接着放入队列中的下一个进程。我们称这个行为叫做 进程的切换。简单地说,就是切换CPU上的进程。

但以上是很笼统的理解。要真正理解他的工作细节,需要明白一个CPU中都有一个寄存器,而寄存器是用来存放进程留下的临时数据的,我们把在CPU内部寄存器的和进程相关的所有内容叫做 硬件上下文。比如说进程A进入CPU时,会在寄存器中存下进程A产生的临时数据,那么当进程A从CPU上剥离的时候也要让进程A带走他的临时数据,否则就会被后来的进程B的硬件上下文给覆盖掉,那么等下次又轮到进程A调度的时候,他的数据就会丢失。

进程的调度

一个CPU拥有一个Runqueue(运行队列)

Linux2.6内核中进程调度队列的数据结构

观察上图的队列结构,重点放在蓝色框框红色框框

单独观察框内元素有:nr_active、bitmap[5]、queue[140]

这三个元素的具体作用会在【CPU的调度算法原理】中清楚说明。

CPU的调度算法原理

这里讲的是进程在如何在CPU中被调度的,他的原理是什么。Runqueue运行队列是Linux系统内核中非常重要的一个组成部分。它是用于管理所有的进程和线程的队列,使它们能够按照特定的优先级被调度执行。

优先级队列一共有140个元素(注意这里的优先级队列是嵌套在runqueue中的queue[140],这里不要搞混了)。在CPU调度的时候,就是要排查queue中所有不为空位置,也就是没有进程需要被调度。

为了更高效的查找队列的每个位置上是否为空(无进程),因此就有了bitmap[5](位图),他的数据类型是unsighed,所以他的总大小为160个bit位(5 x 32 = 160),但我们只用140个bit位 ,这个位图 就跟二进制序列一样,例如:011100010.... 1就代表队列不为空,0就代表为空。 所以我们就把遍历队列的工作简化为了对位图的操作。通过位图 就可以每跨32位找一次,提升了效率。

在系统中进程的优先级(pri)大小范围是 [ 60,99],也就是40个优先级顺序位置,如上图所示,runqueue的结构里有一个大小140位的queue。系统会根据这140个优先级不同,将进程列入到不同的队列当中,每一个队列标记着一个优先级,

如右图所示,后40个bit位,从100位到139位,从上到下遍历所有的队列是否为空,不为空,CPU就调度此处队列链起来的进程。 进程PCB的双链表结构 比较特殊,可以点击链接进行了解。 虽然优先级的范围是60 --> 99,而右侧图片中红色数组优先级区域的范围是100 --> 139,但不影响pri+40映射到数组的下标,这其实用了一个开散列的哈希表。 注意:每一个数组的节点对应的是一个队列头节点,而这每一个队列里都可以有多个进程。在相同的优先级的进程当中才用FIFO算法调度。

每一个节点通过这个双链表将进程PCB连起来。

补充:优先级队列的前100位是针对实时进程的,而后40位是管普通进程的

接着观察runqueue的结构图,可以看见有红色区域和蓝色区域分别有两个140队列:

两个队列的分工:

  • 活跃队列:放时间片未用完的就绪进程;CPU只在这里选进程运行。
  • 过期队列:放时间片已用完的进程;新就绪的普通进程也放这里。

红色数组蓝色数组又嵌套在一个arrays[2]的结构体数组中,再有两个指针分别是:

  • active:指向第一组队列(活跃),就是图片中蓝色区域的
  • expired:指向第二组队列(过期),即红色

为什么这样设计呢?因为CPU只看活跃队列,按优先级进程。当时间片用完,那么这时中需要将active* 和 expired*指向的内容swap,也就是交换一下,那么CPU就可以调度原来的过期队列了,轮流反复。这样的设计就可以避免低优先级队列得不到调度的问题(饥饿问题)!!!

在我们包裹着优先级队列的array数组当中还有一个nr_active调度器,也叫计数器。用来统计当前array数组内所有队列中就绪进程的总数量,如果nr_active为0,那么就直接交换active*和expired*。

以上差不多就是时间片+优先级轮转调度算法,时间复杂度为O(1)。

http://www.jsqmd.com/news/696795/

相关文章:

  • Qwen3-4B-Instruct详细步骤:自定义system prompt与角色设定
  • Github好用项目系列(2)Spec Kit:驱动规范的开发如何颠覆传统的软件开发模式
  • 2026插座买什么牌子的好?安全耐用品牌推荐 - 品牌排行榜
  • 别再滥用keep-alive了!聊聊Vue 3中那些被忽略的缓存策略与性能陷阱
  • 2026年3月美妆加盟品牌推荐,美妆加盟公司 - 品牌推荐师
  • Pixel Language Portal应用场景:开发者社区多语种技术问答智能路由系统
  • 将 Kubernetes 理念引入端侧 AI:探索侠客工坊百万级“数字员工”节点的远程调度与自愈架构
  • 2025_NIPS_EA3D: Online Open-World 3D Object Extraction from Streaming Videos
  • 3分钟搭建自己的电话号码定位系统:免费开源解决方案完全指南
  • GTE-Pro入门必看:GTE-Large训练目标与对比学习损失函数解析
  • 如何构建灵活稳定的Android插件架构:RePlugin的完整实践指南
  • Oumuamua-7b-RP多场景:跨境电商客服质检、日语配音脚本生成、字幕润色
  • Qwen3-TTS-Tokenizer-12Hz保姆级教程:Web界面上传失败的5种排查方案
  • 如何快速解决Blender与3D打印机兼容问题:完整Blender3mfFormat使用指南
  • 代码块 —— 外在定义 及 主要作用
  • Qwen3-ASR-0.6B实战案例:为盲人用户开发语音笔记助手(含方言支持)
  • 机器学习算法核心六问:从原理到实践
  • Node.js项目快速搭建终极指南:Koa-Generator实战手册
  • YOLOv11改进 | Neck篇 | CVPR最新低照度图像增强模块HVI改进YOLOv11(有效涨点)
  • 【高届数机械工程会议】第十二届机械工程、材料和自动化技术国际学术会议(MMEAT 2026)
  • Phi-3.5-Mini-Instruct Streamlit部署优化:模型预加载+缓存加速方案
  • Qianfan-OCR快速上手指南:JPG/PNG/WEBP多格式文档图片解析三分钟搞定
  • 别再死磕PID了!用Python+MPC给机械臂做个‘未来视’控制器(附ROS2实战代码)
  • Qwen3.5-4B-AWQ代码实例:Python调用API+WebUI交互+日志排查全流程
  • Real Anime Z开源价值解读:Z-Image底座+Real Anime Z微调的协同优势
  • 神经网络常见层Numpy封装参考(4):优化器
  • LM多场景落地案例:婚纱摄影公司AI试衣间原型系统构建过程
  • ARGO:开源本地优先AI智能体平台部署与应用全指南
  • FLUX.1-Krea-Extracted-LoRA部署教程:CUDA12.4+PyTorch2.5.0环境兼容性验证
  • Qwen3-ASR-0.6B实际作品集:跨语言会议纪要+中英双语字幕生成