☰
μC/OS-II 实时系统概念零基础入门(一):从前后台系统到任务调度、同步与通信
2026/10/19 3:41:32 网站建设 项目流程

本文以《嵌入式实时操作系统 μC/OS-II》第 2 章“实时系统概念”为主线,从前后台系统开始,逐步理解任务、调度、抢占、临界区、信号量、优先级反转、任务通信、中断和时钟节拍。文章适合第一次接触 RTOS 的读者,也可以作为后续学习 μC/OS-II 源码与 API 前的复习提纲。

目录

  • 一、实时系统到底“实时”在哪里
  • 二、从前后台系统走向多任务系统
  • 三、任务、状态、栈与上下文切换
  • 四、内核如何完成任务调度
  • 五、临界区、共享资源与互斥
  • 六、优先级反转与死锁
  • 七、任务同步与任务间通信
  • 八、中断、时钟节拍与延时误差
  • 九、用电机控制系统串起全部概念
  • 十、易错点与复习提纲
  • 十一、总结

一、实时系统到底“实时”在哪里

1. 实时不等于单纯运行得快

“实时系统”最容易被误解成“速度特别快的系统”。实际上,实时系统真正强调的是:

系统能否在规定的时间限制内,对事件作出确定、可预测的响应。

假设电机驱动器检测到过流后,要求在100 μs100\ \mu s100μs内关断 PWM。某系统每次都能在20∼80 μs20\sim 80\ \mu s20∼80μs内完成保护,即使平均速度不是最快,它仍然具有较好的实时性。反过来,另一个系统平均只需10 μs10\ \mu s10μs,却偶尔需要2 ms2\ ms2ms,那么它可能无法满足保护要求。

设事件发生时刻为tet_ete​,任务真正开始处理该事件的时刻为tst_sts​,则响应时间可以写成:

tr=ts−te t_r=t_s-t_etr​=ts​−te​

实时系统关心的不只是平均响应时间,还关心最坏情况下的响应时间:

tr,max⁡≤D t_{r,\max}\leq Dtr,max​≤D

其中,DDD是任务允许的截止时间(Deadline)。

2. 硬实时与软实时

根据错过截止时间造成的后果,可以把实时系统粗略分为两类。

类型主要特点典型应用
硬实时系统一旦错过截止时间,可能产生不可接受的后果保护装置、安全控制、飞行控制
软实时系统偶尔错过截止时间会降低性能,但通常不会立即造成灾难显示刷新、音视频播放、普通通信

实际系统往往同时包含两者。例如,电流保护任务接近硬实时,而液晶显示任务通常属于软实时。

二、从前后台系统走向多任务系统

1. 什么是前后台系统

传统单片机程序常写成一个无限循环:

intmain(void){Hardware_Init();while(1){Key_Scan();Data_Process();CAN_Transmit();Display_Update();}}

其中:

  • while(1)中循环执行的程序称为后台(Background);
  • 由硬件事件触发的中断服务程序 ISR 称为前台(Foreground)。

前后台系统的执行关系

CPU 平时运行后台循环。ADC、定时器或串口等外设产生中断后,CPU 暂停后台程序,转入 ISR;ISR 执行结束后,再返回原来的程序。

2. 前后台系统为什么会遇到瓶颈

假设主循环如下:

while(1){OLED_Update();// 最坏执行时间 10 msCAN_Process();// 最坏执行时间 2 msKey_Scan();// 最坏执行时间 1 msMotor_Control();// 希望每 100 us 执行一次}

Motor_Control()必须等前面的函数执行完才能运行。只要显示刷新时间发生变化,控制函数的响应时间也会变化。前后台系统的主要问题并不是“绝对不能用”,而是:

  • 重要功能的执行时刻容易受其他代码影响;
  • 主循环变长后,最坏响应时间难以估计;
  • 各功能之间耦合较强,维护一个模块可能改变整个循环周期;
  • 复杂系统中的同步、通信和资源保护需要程序员自行管理。

对于功能简单、时序要求不高的产品,前后台系统仍然有效;当任务数量增加、响应时间要求变严格时,引入实时内核通常更容易管理。

3. 多任务系统不等于真正并行

在单核 MCU 中,任意一个瞬间只能执行一个任务。所谓多任务,是 CPU 在多个任务之间快速切换:

T1→T2→T3→T1→⋯ T_1\rightarrow T_2\rightarrow T_3\rightarrow T_1\rightarrow \cdotsT1​→T2​→T3​→T1​→⋯

多个任务在一段时间内交替推进,称为并发(Concurrency);多个处理器核心在同一时刻分别执行不同任务,才是严格意义上的并行(Parallelism)。

μC/OS-II 主要解决的是单处理器上的多任务并发管理。

三、任务、状态、栈与上下文切换

1. 任务不只是一个函数

任务通常以一个不会返回的函数表示:

voidMotorTask(void*pdata){(void)pdata;while(1){Motor_Control();OSTimeDly(1);}}

从操作系统角度看,一个任务至少包含:

任务=代码+优先级+状态+CPU现场+私有栈+控制信息 \text{任务}=\text{代码}+\text{优先级}+\text{状态}+\text{CPU现场}+\text{私有栈}+\text{控制信息}任务=代码+优先级+状态+CPU现场+私有栈+控制信息

μC/OS-II 使用任务控制块 TCB(Task Control Block)保存任务管理信息。任务栈则保存局部变量、函数返回地址、CPU 寄存器和被切换时的运行现场。

2. 任务的基本状态

初学时先掌握三个核心状态:

  • 就绪态 Ready:运行条件已经满足,只差 CPU 使用权;
  • 运行态 Running:当前正在占用 CPU;
  • 等待态 Waiting:正在等待时间、事件、消息或资源,暂时不能参与调度。

此外,教材还给出了睡眠态(任务尚未建立或已被删除)以及被中断态等状态。

μC/OS-II 任务状态与主要转换条件

任务状态变化通常由以下事件引起:

  • 创建任务:睡眠态进入就绪态;
  • 调度器选中任务:就绪态进入运行态;
  • 调用延时或等待函数:运行态进入等待态;
  • 延时到期、收到信号或消息:等待态进入就绪态;
  • 更高优先级任务就绪:当前任务被抢占,运行态回到就绪态;
  • 中断到来:运行任务暂时进入被中断状态。

需要特别注意:就绪并不等于正在执行。就绪任务可能有多个,但单核 CPU 同一时刻只有一个运行任务。

3. 为什么每个任务都要有独立栈

任务运行时会产生自己的局部变量、函数调用层次和 CPU 现场。如果所有任务共用一套栈,任务切换后原来的调用现场会被破坏。因此,每个任务都要分配独立的栈空间。

创建任务时常见的写法如下:

#defineTASK_STK_SIZE256uOS_STK MotorTaskStk[TASK_STK_SIZE];OSTaskCreate(MotorTask,NULL,&MotorTaskStk[TASK_STK_SIZE-1u],5u);

这里传入的并不是普通数据数组,而是MotorTask的专用任务栈。示例按栈向低地址增长的常见移植方式传入栈顶,实际写法应以具体 CPU 端口为准。

4. 上下文切换到底保存了什么

上下文(Context)是任务被暂停时的 CPU 运行现场,通常包含:

  • PC:程序计数器,决定任务从哪条指令继续执行;
  • SP:栈指针,指向该任务当前栈位置;
  • 通用寄存器;
  • 状态寄存器或程序状态字;
  • 特定处理器要求保存的其他寄存器。

任务上下文切换与独立任务栈

任务切换可以概括为:

任务切换=保存旧任务现场+选择新任务+恢复新任务现场 \text{任务切换}=\text{保存旧任务现场}+\text{选择新任务}+\text{恢复新任务现场}任务切换=保存旧任务现场+选择新任务+恢复新任务现场

任务切换不是零成本操作。CPU 寄存器越多、移植层保存的内容越多,切换开销通常越大。因此,不能只看“每秒能切换多少次”,还要结合 CPU 架构、编译器、任务栈和实际应用评价系统性能。

四、内核如何完成任务调度

1. 内核与调度器分别做什么

内核(Kernel)负责管理任务、分配 CPU 时间、处理任务之间的同步和通信。调度器(Scheduler)是内核中负责选择下一个运行任务的部分。

μC/OS-II 的核心调度规则可以写成:

CPU运行所有就绪任务中优先级最高的任务 \boxed{\text{CPU运行所有就绪任务中优先级最高的任务}}CPU运行所有就绪任务中优先级最高的任务​

在 μC/OS-II 中,优先级数值越小,优先级越高。例如:

任务优先级数值当前状态
电流控制任务5Ready
CAN 通信任务10Ready
显示任务20Running

由于5<10<205<10<205<10<20,调度器应让电流控制任务运行。当前显示任务将失去 CPU 使用权并回到就绪态。

2. 不可抢占型内核

在不可抢占型内核中,即使高优先级任务已经就绪,也必须等待当前任务主动释放 CPU,才能开始运行。

不可抢占型内核的任务响应过程

它的优点是任务切换位置比较明确,共享数据保护相对容易;缺点是高优先级任务的响应时间受当前任务影响,最坏响应时间可能较长。

3. 可抢占型内核

在可抢占型内核中,只要更高优先级任务进入就绪态,当前低优先级任务就会被挂起,高优先级任务立即获得 CPU。

可抢占型内核的任务响应过程

μC/OS-II 属于基于优先级的可抢占式实时内核。它的主要价值是让高优先级任务的响应时间更确定,但同时也要求程序正确保护共享资源。

4. 抢占通常发生在什么时刻

常见触发点包括:

  • ISR 发布信号量、消息或事件,使高优先级任务就绪;
  • 任务释放互斥资源,使等待该资源的高优先级任务就绪;
  • 延时到期,高优先级任务重新进入就绪态;
  • 创建或恢复了一个更高优先级任务。

中断结束后不一定返回被中断的任务。如果 ISR 唤醒了更高优先级任务,OSIntExit()可能触发一次调度,CPU 会直接运行该高优先级任务。

5. 可重入函数为什么重要

可抢占系统中,一个函数可能在尚未执行完成时,再次被另一个任务或 ISR 调用。若多次调用互不破坏彼此的数据,该函数称为可重入函数(Reentrant Function)。

不可重入函数常见原因包括:

  • 修改未保护的全局变量或静态变量;
  • 返回指向同一静态缓冲区的指针;
  • 使用不能并发访问的外设;
  • 调用了其他不可重入函数。

下面的函数依赖共享静态变量,因此不是天然可重入的:

intGetNextValue(void){staticintvalue=0;value++;returnvalue;}

改进方向包括使用局部变量、由调用者提供缓冲区,或者使用互斥机制保护共享状态。

6. 时间片轮转与 μC/OS-II 的关系

时间片轮转是指同优先级任务轮流占用 CPU,每个任务运行一个时间片后切换到下一个任务。它常用于通用操作系统,以改善同优先级任务之间的公平性。

经典 μC/OS-II 采用固定优先级抢占调度,并要求每个任务具有唯一优先级。因此,理解时间片有助于比较不同操作系统,但不能把通用操作系统的“同优先级轮转”直接套用到经典 μC/OS-II 上。

五、临界区、共享资源与互斥

1. 什么是资源与共享资源

任务运行时使用的变量、缓冲区、串口、SPI、ADC、文件和存储区都可以称为资源。如果一个资源可能被多个任务或 ISR 使用,它就是共享资源。

共享资源并不一定立刻出错,真正的问题是:多个执行单元能否在没有保护的情况下交错访问它。

2. 一句count++为什么也不安全

count++;

这条 C 语句通常不是一条不可分割的 CPU 指令,而可能被分解为:

  1. 从内存读取count;
  2. 在寄存器中执行加一;
  3. 将结果写回内存。

如果任务和 ISR 在中间发生交错(均读取到5),两次加一可能只产生一次有效结果。

count被中断后产生的竞态条件

最终结果依赖执行先后顺序的现象称为竞态条件(Race Condition)。

3. 什么是临界区

临界区是访问共享资源、且不能被相关执行单元同时进入的一段代码。最直接的保护方式是短时间关闭中断:

OS_CPU_SR cpu_sr;OS_ENTER_CRITICAL();shared_count++;OS_EXIT_CRITICAL();

临界区必须尽量短。长时间关闭中断会增加中断延迟,破坏系统实时性。不能把耗时计算、串口轮询发送或等待外设完成放在关闭中断的区域内。

4. 常见保护手段的区别

方法适用场景主要注意事项
关闭中断任务与 ISR 共享极短数据临界区必须非常短
锁调度器防止任务切换,但允许中断响应ISR 仍可能访问共享数据
信号量事件计数、同步,也可用于简单互斥不一定具有所有权语义
互斥信号量多任务共享资源关注优先级反转处理机制
消息传递尽量避免直接共享数据需要设计消息生命周期和缓冲区

不要看到共享变量就一律关闭中断。应先判断竞争双方是谁:

  • 任务与 ISR 竞争:普通任务级互斥锁通常保护不了 ISR;
  • 任务与任务竞争:互斥信号量通常比长时间关闭中断更合适;
  • 单写者、多读者且数据天然原子:可能只需保证可见性与一致性;
  • 多字节或复合结构更新:要保证读者不会看到“更新一半”的状态。

六、优先级反转与死锁

1. 优先级反转是怎样发生的

假设有三个任务:

  • 高优先级任务 H;
  • 中优先级任务 M;
  • 低优先级任务 L。

任务 L 先获得共享资源 R。随后任务 H 就绪并抢占 L,但 H 也需要 R,只能进入等待态。此时 L 本应继续运行并尽快释放 R,却又被不需要 R 的任务 M 抢占。结果是高优先级任务 H 间接等待中优先级任务 M 完成。

中优先级任务延长高优先级任务等待时间

这就是优先级反转:高优先级任务的实际进度反而受低优先级任务控制。

教材中的完整时序关系如下。

优先级反转的任务时序(教材原图裁剪)

2. 如何缓解优先级反转

常见方案包括:

  • 优先级继承:低优先级任务占有高优先级任务所需资源时,临时继承较高优先级;
  • 优先级天花板:任务获得互斥资源后,优先级临时提升到预先设定的上限;
  • 缩短持锁时间;
  • 避免在持锁期间等待其他事件;
  • 用消息传递减少资源共享。

不同 μC/OS-II 版本及其互斥量实现采用的优先级处理方式可能不同,使用时应以对应版本手册和OSMutex...实现为准,不能把二值信号量和互斥量完全等同。

3. 死锁是怎样发生的

假设:

  • 任务 T1 已占有资源 R1,同时等待 R2;
  • 任务 T2 已占有资源 R2,同时等待 R1。

两个任务都不会主动释放已经占有的资源,于是系统永久等待。这就是死锁。

工程中常用的预防方法有:

  1. 所有任务按统一顺序申请多个资源;
  2. 一次取得全部资源后再开始操作;
  3. 按申请的相反顺序释放资源;
  4. 为等待操作设置合理超时,并处理超时后的清理;
  5. 尽量避免嵌套持有多个互斥资源。

超时只能帮助系统发现和恢复部分死锁,并不能替代正确的资源顺序设计。

七、任务同步与任务间通信

同步解决“什么时候可以继续执行”,通信解决“要传递什么数据”。在 RTOS 中,两者经常一起出现,但概念不能混淆。

1. 信号量:同步、计数与简单互斥

信号量可以理解为内核维护的计数值。任务调用Pend获取信号量,没有可用信号量时进入等待态;任务或 ISR 调用Post释放信号量,并可能唤醒等待任务。

OS_EVENT*AdcSem;voidSystem_Init(void){AdcSem=OSSemCreate(0u);}voidAdcTask(void*pdata){INT8U err;(void)pdata;while(1){OSSemPend(AdcSem,0u,&err);if(err==OS_ERR_NONE){Process_ADC_Data();}}}

如果初值为 0,任务会一直等待,直到 ISR 或其他任务发布一次信号量。这种用法主要表达“事件已经发生”。如果把信号量用于互斥,还要认真考虑所有权和优先级反转问题。

2. 事件标志组:等待多个条件的组合

一个任务可能需要等待多个事件。例如:

  • “ADC 完成”或“通信收到数据”,任意一个发生即可继续;
  • “参数加载完成”并且“母线电压正常”,两个条件都满足才能启动。

事件标志组把多个事件映射为不同位,并支持 OR、AND 等组合等待。

事件标志组的 OR 型与 AND 型同步(教材原图裁剪)

信号量更适合表示事件计数或单个资源;事件标志组更适合表示多个布尔条件的组合。

3. 消息邮箱:传递一个消息指针

消息邮箱可以保存一个消息指针。发送任务把指针放入邮箱,接收任务从邮箱取出指针。若邮箱为空,接收任务可以等待;若邮箱已有消息,再次投递通常需要处理“邮箱已满”错误。

消息邮箱的基本传递关系(教材原图裁剪)

常见服务包括:

  • OSMboxCreate():建立邮箱;
  • OSMboxPost():投递消息;
  • OSMboxPend():等待消息;
  • OSMboxAccept():非阻塞地检查邮箱。

邮箱传递的通常是指针,而不是自动复制整块数据。因此必须保证消息所指向的对象在接收者使用完之前仍然有效。

4. 消息队列:让多条消息排队

消息队列可以看成邮箱的扩展。邮箱只能保存一个消息指针,队列可以保存多个消息指针。

典型服务包括:

  • OSQCreate():建立消息队列;
  • OSQPost():从队尾投递消息;
  • OSQPostFront():从队首投递消息;
  • OSQPend():等待并取出消息;
  • OSQAccept():非阻塞地检查消息。

5. 常用同步与通信机制对比

机制是否携带数据能否累计多个事件/消息典型用途
二值信号量否通常只表示 0/1 状态ISR 唤醒任务、简单同步
计数信号量否可以计数资源数量、事件累计
互斥信号量否不用于事件累计保护共享资源
事件标志组携带多个布尔位可以组合多个条件等待 OR/AND 条件
消息邮箱一个消息指针只能保留一个待取消息传递最新命令或对象指针
消息队列多个消息指针可以排队数据包、命令流、采样结果

选择机制时先问三个问题:

  1. 需要传递的是“事件”还是“数据”?
  2. 事件或数据能否丢失、覆盖或合并?
  3. 发送者和接收者是否需要阻塞等待?

八、中断、时钟节拍与延时误差

1. 中断与任务的关系

ISR 可以打断普通任务,但 ISR 本身不是普通任务。ISR 应尽量只完成必要的硬件处理,例如:

  • 读取外设状态并清除中断标志;
  • 取走 ADC、串口或定时器数据;
  • 发布信号量、事件标志或消息;
  • 让复杂处理转移到高优先级任务中完成。

典型结构如下:

voidADC_ISR(void){OSIntEnter();ADC_ClearInterruptFlag();SampleBuffer=ADC_ReadResult();OSSemPost(AdcSem);OSIntExit();}

该代码只用于说明结构,寄存器保护、中断声明、向量表和清标志顺序应根据具体 MCU 移植层调整。

ISR 中通常不能调用会使当前执行单元阻塞的Pend类函数,因为 ISR 没有普通任务那样可以挂起和恢复的调度语义。

2. 为什么中断退出后不一定回原任务

假设低优先级显示任务正在运行,ADC 中断到来后发布信号量,使高优先级控制任务进入就绪态。OSIntExit()检查到更高优先级任务已经就绪,就会触发调度:

低优先级任务→ADC ISR→高优先级控制任务 \text{低优先级任务}\rightarrow\text{ADC ISR}\rightarrow\text{高优先级控制任务}低优先级任务→ADC ISR→高优先级控制任务

高优先级任务完成或进入等待态后,低优先级任务才有机会继续运行。

3. 什么是时钟节拍

时钟节拍(Clock Tick)是周期性到来的操作系统时基。若系统每秒产生OS_TICKS_PER_SEC次节拍,则节拍周期为:

Ttick=1OS_TICKS_PER_SEC T_{tick}=\frac{1}{\text{OS\_TICKS\_PER\_SEC}}Ttick​=OS_TICKS_PER_SEC1​

例如:

OS_TICKS_PER_SEC=100 \text{OS\_TICKS\_PER\_SEC}=100OS_TICKS_PER_SEC=100

则:

Ttick=10 ms T_{tick}=10\ msTtick​=10ms

节拍 ISR 中通常调用OSTimeTick()更新任务延时,并在退出中断时根据需要重新调度。

4.OSTimeDly(1)不一定精确延时一个完整节拍

任务调用延时函数的时刻可能位于两个节拍中断之间。若刚过一个 Tick 就调用OSTimeDly(1),实际等待接近一个节拍;若在下一个 Tick 即将到来时调用,实际等待可能接近 0。

调用相位不同导致的节拍延时量化误差

在没有其他抢占影响时,可以近似理解为:

0<Tdelay≤Ttick 0<T_{delay}\leq T_{tick}0<Tdelay​≤Ttick​

若任务必须至少等待一个完整节拍,通常需要请求两个节拍;若系统中还有高优先级任务和中断,任务重新获得 CPU 的时刻还可能进一步推迟。

因此,操作系统节拍适合任务级定时和超时管理,不应直接代替高精度 PWM、ADC 触发或控制环定时器。

九、用电机控制系统串起全部概念

假设一个控制器包含以下功能:

功能触发方式建议执行位置优先级思路
ADC 采样完成ADC 中断ISR 中取数并唤醒控制任务ISR 快速完成
电流控制与 PWM 更新信号量唤醒高优先级任务最高任务优先级
故障处理比较器或保护中断ISR 快速关断,任务记录故障高
CAN 通信接收中断加通信任务中断收包,任务解析中
参数存储消息或事件触发后台任务低
OLED 刷新周期延时低优先级任务最低

一种典型执行过程如下:

  1. ADC 转换完成并进入 ISR;
  2. ISR 保存采样结果,发布AdcSem;
  3. 高优先级控制任务由等待态进入就绪态;
  4. OSIntExit()发现控制任务优先级更高,发生任务切换;
  5. 控制任务计算电流环并更新 PWM;
  6. 控制任务再次等待AdcSem;
  7. CAN 或显示等低优先级任务继续运行。

控制任务的结构可以写成:

voidCurrentControlTask(void*pdata){INT8U err;(void)pdata;while(1){OSSemPend(AdcSem,0u,&err);if(err==OS_ERR_NONE){Current_Sample_Process();Current_Loop_Calculate();PWM_Update();}}}

这里最重要的设计思想不是“把所有代码都放进任务”,而是:

  • ISR 负责快速响应硬件;
  • 高优先级任务负责确定性的实时计算;
  • 低优先级任务处理显示、记录和非关键通信;
  • 任务之间通过信号量、事件或消息连接;
  • 共享外设和共享数据必须有明确的保护策略。

对于10 kHz10\ kHz10kHz、20 kHz20\ kHz20kHz等高速电流环,是否放入 RTOS 任务还要结合 CPU 性能、任务切换开销和抖动指标判断。很多系统仍会在高频 ISR 中完成最核心、执行时间固定的控制算法,而把通信、状态机和慢速环放到任务中。RTOS 不是为了机械地替换全部中断,而是帮助系统分层管理实时工作。

十、易错点与复习提纲

1. 高频易错点

误区一:实时系统就是执行速度快。

实时系统强调最坏响应时间可预测,并且能够满足截止时间。

误区二:任务处于 Ready 就是在运行。

Ready 只表示具备运行条件;单核 CPU 同一时刻只能有一个 Running 任务。

误区三:中断结束一定返回原任务。

ISR 如果唤醒了更高优先级任务,中断退出时可能直接切换到该任务。

误区四:一行 C 语句一定是原子操作。

count++、结构体赋值和多字节变量访问都可能由多条机器指令组成。

误区五:信号量与互斥量完全相同。

信号量可用于事件计数和同步;互斥量强调资源所有权,并可能包含处理优先级反转的机制。

误区六:延时一个 Tick 就是精确延时一个 Tick。

节拍量化会造成相位误差,任务重新运行还会受到更高优先级任务影响。

误区七:任务优先级越大越高。

在 μC/OS-II 中,优先级数值越小,优先级越高。

2. 一张表记住整章逻辑

核心问题对应概念一句话理解
CPU 给谁使用调度、优先级、抢占最高优先级就绪任务运行
任务如何暂停再继续上下文、任务栈、TCB保存旧现场,恢复新现场
多个任务如何安全访问数据临界区、互斥量同一时刻只允许一个执行单元访问
任务如何等待事件信号量、事件标志条件不满足时进入等待态
任务如何传递数据邮箱、消息队列通过内核传递消息指针
中断怎样连接任务ISR、Post、OSIntExitISR 快速处理并唤醒任务
延时怎样计算Tick、OSTimeDly延时精度受节拍量化影响
高优先级为何可能被拖延优先级反转低优先级任务占有共享资源

3. 自测问题

  1. 为什么实时系统不能只比较平均运行速度?
  2. Ready、Running、Waiting 三种状态有什么区别?
  3. 为什么每个任务必须有自己的栈?
  4. 可抢占型内核如何处理刚刚就绪的高优先级任务?
  5. count++为什么可能产生竞态条件?
  6. 信号量用于同步和用于互斥时,含义有什么区别?
  7. 邮箱和消息队列的核心差别是什么?
  8. 为什么OSTimeDly(1)的实际延时可能远小于一个完整 Tick?
  9. 优先级反转中,中优先级任务为什么会进一步延长高优先级任务的等待时间?
  10. ISR 为什么不应该执行耗时操作或调用阻塞式等待函数?

如果能够不用背定义、而是结合任务状态和执行时间线回答这些问题,说明第 2 章的基本框架已经建立。

十一、总结

μC/OS-II 的知识点很多,但第 2 章最终围绕两个核心问题展开:

谁在什么时候获得CPU? \boxed{\text{谁在什么时候获得CPU?}}谁在什么时候获得CPU?​

以及:

多个任务怎样安全地等待、共享和传递信息? \boxed{\text{多个任务怎样安全地等待、共享和传递信息?}}多个任务怎样安全地等待、共享和传递信息?​

理解这两个问题后,后续各章会自然对应起来:

  • 任务管理解决任务的创建、删除、挂起和恢复;
  • 时间管理解决延时与超时;
  • 事件控制块为等待机制提供统一基础;
  • 信号量和互斥量解决同步与资源保护;
  • 事件标志组解决多个条件的组合等待;
  • 邮箱和消息队列解决任务间数据传递;
  • 内存管理解决固定内存块的分配与回收;
  • 移植章节说明任务切换、中断和栈如何落到具体 CPU 上。

学习 RTOS 时,不必一开始死记全部 API。先把“任务状态如何变化、什么时候发生调度、为什么需要保护共享资源”想清楚,再去看函数原型和内核源码,会容易很多。

参考资料

  1. Jean J. Labrosse,《嵌入式实时操作系统 μC/OS-II(第 2 版)》第 2 章:实时系统概念。
  2. μC/OS-II 源码中的任务管理、时间管理、信号量、事件标志组、邮箱、消息队列及移植接口。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询