Mutex 保护临界区
Mutex(互斥锁)用于保护共享资源,确保同一时间只有一个任务能够访问临界区。 防止并发访问导致的数据竞争和资源破坏。
在 HRTOS v2 中,资源分配通过 mutex、调度器和优先级继承机制实现任务级资源仲裁, 而不是简单的内存池模拟。资源分配是确保系统稳定性和可靠性的关键机制。
系统运行两个任务:高优先级任务 task_A 和低优先级任务 task_B,通过 mutex 保护共享资源。 验证在资源竞争情况下,通过优先级继承机制避免优先级反转,确保系统实时性。
资源分配是 RTOS 系统稳定性的关键基础
在嵌入式实时系统中,资源分配的核心不在于"分配算法",而在于"调度器介入 + 阻塞机制 + 优先级继承"。 所有资源竞争必须进入内核仲裁路径,而不是用户态轮询。这是 RTOS 稳定性的关键基础。
Mutex(互斥锁)用于保护共享资源,确保同一时间只有一个任务能够访问临界区。 防止并发访问导致的数据竞争和资源破坏。
当高优先级任务被低优先级任务阻塞时,通过优先级继承机制临时提升低优先级任务的优先级, 避免优先级反转问题,确保系统实时性。
资源竞争直接触发任务状态变化,从 Running 状态进入 Blocked 状态。 调度器根据优先级和资源状态重新选择就绪任务执行。
当任务释放资源后,调度器检查阻塞队列,唤醒等待该资源的高优先级任务, 实现资源的合理分配和任务的公平调度。
HRTOS 如何实现资源分配
在 HRTOS v2 中,资源分配的实现围绕 Mutex 保护、优先级继承、调度器介入和资源释放四个核心环节展开。 每个环节都经过精心设计,确保资源管理的高效性和可靠性。
保护内容:共享资源、临界区代码、数据结构
保护方式:互斥锁(Mutex)机制
锁定时机:任务访问共享资源前
设计考虑:最小化临界区范围,减少锁竞争
继承条件:高优先级任务被低优先级任务阻塞
继承方式:临时提升持有锁任务的优先级
恢复时机:任务释放锁后恢复原优先级
解决目标:避免优先级反转,保证实时性
介入条件:资源竞争、锁不可用
状态转换:Running → Blocked
阻塞队列:维护等待资源的任务
调度策略:基于优先级的资源分配
释放操作:任务释放 Mutex 锁
唤醒机制:检查阻塞队列,唤醒等待任务
调度触发:重新评估就绪任务优先级
状态转换:Blocked → Ready
资源申请到释放的完整执行路径
资源分配的完整实现
task_A 和 task_B 任务函数,通过 mutex 保护共享资源
#include "hrtos.h"
#define TASK_A 1
#define TASK_B 2
#define MUTEX_ID 0
sbit LED_OK = P1^0;
sbit LED_FAIL = P1^1;
/* 高优先级任务 */
void task_A(void)
{
while(1)
{
os_mutex_lock(MUTEX_ID);
/* critical section */
LED_OK = ~LED_OK;
os_mutex_unlock(MUTEX_ID);
os_delay(10);
}
}
/* 低优先级任务(可能阻塞高优先级资源) */
void task_B(void)
{
while(1)
{
os_mutex_lock(MUTEX_ID);
os_delay(50); // 模拟持锁延迟
LED_FAIL = ~LED_FAIL;
os_mutex_unlock(MUTEX_ID);
}
}
hrtos_main 函数,初始化 mutex 并创建两个任务
void hrtos_main(void)
{
LED_OK = 0;
LED_FAIL = 0;
os_mutex_init(MUTEX_ID);
os_task_create((unsigned int)task_B, TASK_B, 2, 5);
os_task_create((unsigned int)task_A, TASK_A, 3, 5);
}
示例执行后的预期行为
使用本示例时需要关注的关键点
在使用 mutex 之前必须调用 os_mutex_init 进行初始化。 未初始化的 mutex 可能导致不可预期的行为,包括死锁和系统崩溃。
临界区代码应尽可能简短,避免在持有锁的情况下执行耗时操作。 长时间持锁会增加其他任务的等待时间,影响系统响应性。
本示例中 task_A 优先级高于 task_B,用于演示优先级继承机制。 实际应用中应根据任务重要性和实时性要求合理设置优先级。
避免嵌套锁和循环等待,这是死锁的常见原因。 如果必须使用多个锁,应按照固定的顺序获取锁,并确保在所有路径上都能正确释放。
深入学习的相关资源