【Zephyr】Zephyr 操作系统基本原理(调度)
【Zephyr】Zephyr 操作系统基本原理(调度)
本文最后更新于55 天前,其中的信息可能已经过时,如有错误请发送邮件到273925452@qq.com

核心速览

调度的概念

Zephyr 是一个多线程操作系统。线程是调度的基本单位。每个线程都是一个独立的执行流,拥有自己的上下文(如程序计数器、寄存器、栈空间)和优先级。内核的工作就是管理这些线程,并根据调度策略在它们之间切换。

  • 调度程序确定哪个线程被允许在任何时间点执行;这个线程被称为当前线程

  • 调度程序可以在多个时间点更改当前线程的身份,也就是将 CPU 的执行从一个线程切换到另一个线程。这些时间点称为*重新调度点

  • 当线程自愿启动将自身转换为挂起或等待状态的操作时,它就会进入睡眠状态

每当调度程序更改当前线程的身份,或者当前线程的执行被 ISR 替换时,内核首先会保存当前线程的 CPU 寄存器值。当线程稍后恢复执行时,这些寄存器值会被恢复。

调度算法

内核调度程序会选择优先级最高的就绪线程作为当前线程。当存在多个相同优先级的就绪线程时,调度程序会选择等待时间最长的线程

三种调度算法

Zephyr 支持多种调度算法,可以根据应用需求进行选择:

  1. 传统调度器 (Traditional Scheduler):这是默认的调度器,实现了上述的“基于优先级的抢占式调度”和“时间分片”。它使用多个就绪队列,每个优先级一个队列,查找下一个要运行的线程非常高效。
  2. 最早截止期优先调度 (Earliest Deadline First, EDF)
    • 这是一种高级的实时调度算法,通过 CONFIG_SCHED_DEADLINE 启用。
    • 在这种模式下,调度器选择线程的标准不再是固定的优先级,而是截止时间 (Deadline)。拥有最早截止时间的线程将被优先执行。
    • 这对于需要保证任务在特定时间点前必须完成的硬实时系统(Hard Real-time Systems)非常有用。
  3. Meta-IRQ 调度:这是一种特殊的、高优先级的调度方式,允许线程在比所有常规线程都高的优先级(但低于硬件中断)上运行,用于处理非常紧急但又不能在中断服务程序(ISR)中完成的任务。

ISR 的执行优先于线程的执行,因此除非中断已被屏蔽,否则当前线程的执行可能随时被 ISR 取代。这适用于协作型线程和抢占式线程。


就绪队列三种实现

  1. 简单链表(CONFIG_SCHED_SIMPLE
    • 线程数很少(3个以内)、优先级变化不频繁场景
    • 占用极小代码空间(约2KB)
    • 插入/删除操作非常快O(n)
    • 线程数增多时,查找最高优先级线程会变慢

  1. 优先级队列(CONFIG_SCHED_MULTIQ
    • 优先级种类不多、线程数适中
    • RAM 占用较多,每种优先级
    • 查找、调度操作在常数时间级 O(1)
    • 不适用于需按截至时间排序、多核亲和性场景

  1. 红黑树(CONFIG_SCHED_SCALABLE
    • 线程数较多(几十、上百甚至更多)
    • 代码体积约2KB
    • 插入/删除操作稍慢
    • 线程数增多时,查找/插入/删除性能在对数时间级O(log n)

一句话模型 “最小数字优先,协作不抢占,同级看时间片,高优来就走,没人跑 Idle。”

调度方式

协作式时间分片

在协作式调度 (Cooperative Scheduling)中,一个正在运行的线程将一直持有 CPU,直到它主动放弃 CPU 使用权。调度器本身不会强制中断线程。

为了克服这些问题,协作线程可以不时主动放弃 CPU,以允许其他线程执行。线程可以通过两种方式放弃 CPU:

  • 调用 k_yield(): 将线程置于调度程序的就绪线程优先级列表的末尾;
  • 调用 k_sleep(): 线程在指定的时间内处于非就绪状态;

简单比喻: 就像一个开放的讨论组,一个成员(线程)可以一直发言,直到他自己觉得说完了,主动停下来让给别人。如果有人滔滔不绝不肯停,其他人就永远没机会说话。


抢占式时间分片

在抢占式调度 (Preemptive Scheduling)中,调度器(Scheduler) 拥有完全的控制权,可以随时中断一个正在运行的线程,并将 CPU 分配给另一个线程。这种中断(即“抢占”)的发生通常是基于优先级和时间片。

不同优先级:抢占

同优先级:时间片轮转

简单比喻: 就像一个严格的老师管理课堂,每个学生(线程)只有固定的发言时间(时间片)。时间一到,老师会立刻打断,让下一个学生发言。如果有更重要的事(高优先级线程),老师会立即处理。


配置选项

  • CONFIG_TIMESLICING :启用时间片调度功能(仅对“可抢占线程”且在指定优先级范围内生效)

  • CONFIG_TIMESLICE_SIZE: 指定每个时间片长度(单位:系统时钟 tick

  • CONFIG_TIMESLICE_PRIORITY:定义一个阈值优先级(数值,记住:数值越小优先级越高)。

CPU空闲(CPU Idle)机制

概念

在 Zephyr 中,CPU 空闲是电源管理框架的核心部分。当系统中没有任何线程需要运行时(即所有线程都在等待事件、休眠或被挂起),空闲线程(idle thread)就会获得 CPU 控制权。空闲线程的主要职责就是让 CPU 进入低功耗状态,以节省能源。


基本原理

Zephyr 内核在调度器发现没有可执行的应用程序线程时,会切换到内置的空闲线程。这个线程会调用电源管理子系统提供的接口,尝试让 CPU 进入最深的可用睡眠状态。


电源状态

Zephyr 定义了多种电源状态,CPU 可以在空闲时进入这些状态。这些状态通常与处理器的特定低功耗模式相关联。当系统空闲时,电源管理子系统会根据距离下一个定时器事件的时间长短,来决定进入哪种睡眠状态。如果下一个事件很遥远,系统就可以进入更深的睡眠状态,以获得更大的功耗节省。


Tickless Idle(无滴答空闲)

  • 在传统的 RTOS 中,系统定时器(System Tick)会以固定的频率(例如,每 1-10 毫秒)产生中断,即使系统处于空闲状态。这会周期性地唤醒 CPU,造成不必要的功耗。
  • Zephyr 支持 Tickless Idle 模式。在这种模式下,当系统进入空闲状态时,内核会停止周期性的系统定时器中断。同时,它会计算出下一个需要处理的事件(比如一个线程的超时)的确切时间,并对定时器硬件进行编程,使其在那个精确的时刻产生一个中断。
  • 这样,CPU 可以在两个事件之间保持长时间的深度睡眠,而不会被不必要的定时器中断唤醒,从而极大地降低了系统在空闲时的功耗。

配置选项

您可以通过 Kconfig 选项来配置 Zephyr 的电源管理和 CPU 空闲行为。一些关键的配置项包括:

  • CONFIG_PM=y:启用电源管理模块。
  • CONFIG_PM_DEVICE=y:启用设备电源管理,允许外设在不使用时进入低功耗状态。
  • CONFIG_TICKLESS_IDLE=y:启用 Tickless Idle 功能。这是实现高效节能的关键。
  • CONFIG_TICKLESS_KERNEL=y:这是一个更高级的模式,它不仅在空闲时,在线程等待内

了解 Heiweilu的小世界 的更多信息

订阅后即可通过电子邮件收到最新文章。

💡本内容采用 CC BY-NC-SA 4.0 协议,非商业转载需注明作者和出处,商业用途请联系作者授权,衍生作品需采用相同协议。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇

了解 Heiweilu的小世界 的更多信息

立即订阅以继续阅读并访问完整档案。

继续阅读

🎵 背景音乐
点击播放
00:00 00:00