freertos学习笔记12--个人自用-第18章 资源管理(Resource Management)

一:资源管理

除了互斥量(Mutex)之外,如何通过屏蔽中断暂停调度器来实现对临界资源的独占访问。

以下是该章节的核心内容总结:

1. 资源管理的不仅仅是互斥量

虽然之前的章节(如互斥量)介绍了通过“公平竞争”的方式(谁先拿到锁谁用)来保护临界资源,但本章介绍了更“强硬”的方法 :

  • 如果是中断跟任务抢资源:直接屏蔽中断。

  • 如果是其他任务跟当前任务抢资源:直接禁止调度器,阻止任务切换。

二:屏蔽中断(Critical Sections,临界区)

1. 在任务中屏蔽中断 (In Task)

在任务级代码中,我们使用一对宏来定义临界区。

  • 进入临界区taskENTER_CRITICAL()

  • 退出临界区taskEXIT_CRITICAL()

特性:

  • 这两段代码之间,优先级低于或等于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断会被屏蔽 。
  • 由于没有中断,任务调度也就无法进行,当前任务独占 CPU 。
  • 支持嵌套调用:宏内部有计数器,只有当退出次数等于进入次数时,中断才会真正重新开启 

示范代码:

/* 假设这里是一个任务函数 */
void vATaskFunction( void *pvParameters )
{
    for( ;; )
    {
        /* ... 其他非临界代码 ... */

        /* 进入临界区:
         * 执行这句代码后,受管辖的中断被屏蔽,任务调度停止 
         */
        taskENTER_CRITICAL(); 

        /* * --- 访问临界资源 ---
         * 这里是独占式访问,不会被中断打断,也不会被切换到其他任务
         * 注意:这里的代码必须尽可能快速地执行!
         */
        AccessSharedData();

        /* 退出临界区:
         * 重新使能中断,恢复任务调度 
         */
        taskEXIT_CRITICAL(); 

        /* ... 其他代码 ... */
    }
}


2. 在中断服务程序中屏蔽中断 (In ISR)

在中断服务程序(ISR)中,必须使用带有 FROM_ISR 后缀的宏。这一点非常重要,因为 ISR 的运行环境与任务不同。

  • 进入临界区taskENTER_CRITICAL_FROM_ISR()

  • 退出临界区taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus )

关键区别: ISR 版本需要保存进入临界区之前的中断状态。因为进入 ISR 时,某些中断可能已经被硬件或软件关闭了,退出时不能盲目打开所有中断,而是要恢复到之前的状态 。

示范代码:

void vAnInterruptServiceRoutine( void )
{
    /* 定义一个变量,用来记录当前中断是否使能的状态 */
    UBaseType_t uxSavedInterruptStatus;

    /* * 进入临界区:
     * 1. 屏蔽中断
     * 2. 返回进入前的中断状态,保存在变量中
     */
    uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();

    /* * --- 访问临界资源 --- 
     * 这里的代码不会被更高优先级的中断打断(受 FreeRTOS 管理范围内)
     */
    AccessHardwareRegister();

    /* * 退出临界区:
     * 传入之前保存的状态变量,恢复中断状态 
     */
    taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );

    /* 现在,当前 ISR 可以被更高优先级的中断打断了 */
}


3. 注意事项与限制

虽然屏蔽中断使用起来很简单,但它对系统的实时性影响很大,被称为“粗鲁”的方法 。

  1. 执行时间要短:在 ENTEREXIT 之间的代码必须非常快。如果这里卡住了,系统将无法响应其他硬件中断,也无法切换任务,导致系统“卡死”或响应延迟 。

  2. 高优先级中断例外:优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断不会被屏蔽。这意味着这些极高优先级的中断仍然可以发生,但它们绝对不允许调用任何 FreeRTOS 的 API 函数 。

  3. 死锁风险:虽然屏蔽中断本身不会导致普通死锁,但如果临界区内调用了会阻塞的函数(等待队列、延时等),会导致系统彻底崩溃,因为调度器已经被暂停了。

三:暂停调度器

暂停调度器 (Suspending the Scheduler) 是 FreeRTOS 中另一种保护临界资源的方法。

相比于“屏蔽中断”(关中断)那种“一刀切”的霸道做法,暂停调度器显得更“温柔”一些。它的核心思想是:我不关中断,但我禁止任务切换。

1. 核心原理

  • 发生了什么? 当你暂停调度器时,FreeRTOS 的任务调度算法停止工作。这意味着当前正在运行的任务会独占 CPU,没有其他任务(无论优先级多高)能抢占它。

  • 中断还能跑吗? 能! 这是它和“屏蔽中断”最大的区别。硬件中断(如串口接收、定时器溢出)仍然可以正常响应。

  • 适用场景

    • 你要保护的资源仅仅是和其他任务共享的,没有任何中断 ISR 会去碰这个资源。

    • 你的临界区代码比较长,如果关中断会导致系统对外设反应迟钝,但你又必须独占 CPU。

2. 操作函数

FreeRTOS 提供了两个极其简单的函数来实现这一功能 :

  • vTaskSuspendAll( void )

    • 作用:暂停调度器。

    • 后果:从这一刻起,不会发生任务切换。

  • xTaskResumeAll( void )

    • 作用:恢复调度器。

    • 返回值pdTRUE 表示在暂停期间有更高优先级的任务就绪了(意味着恢复瞬间会发生一次任务切换),pdFALSE 表示没有。通常我们在应用层代码中可以忽略这个返回值

3. 示范代码

假设你有一个全局数组 g_SharedArray,多个任务都会去读写它,但没有中断会去碰它。

void vATaskFunction( void *pvParameters )
{
    for( ;; )
    {
        /* ... 这里的代码可以被切换 ... */

        /* 1. 暂停调度器
         * 此时,中断依然开着,但绝不会切换到别的任务去 
         */
        vTaskSuspendAll();

        /* --- 临界区开始 --- */
        
        /* 执行一些耗时较长、涉及多个变量的逻辑运算 */
        ProcessSharedData(); 
        
        /* * 注意:在这里千万不要调用会导致阻塞的 API!
         * 比如不能调 vTaskDelay(), 不能读空队列等。
         * 因为调度器停了,一旦阻塞,系统就死锁了。
         */

        /* --- 临界区结束 --- */

        /* 2. 恢复调度器
         * 如果在暂停期间,有高优先级任务就绪,这里会立即切换过去
         */
        xTaskResumeAll();

        /* ... 这里的代码可以被切换 ... */
    }
}

4. 关键特性与注意事项

  1. 支持嵌套调用

    和屏蔽中断一样,暂停调度器也支持嵌套。FreeRTOS 内部维护了一个计数器。

    • 调用 3 次 vTaskSuspendAll,必须调用 3 次 xTaskResumeAll,调度器才会真正恢复。

    • 这使得你可以在不同的函数中安全地调用它,而不用担心破坏外层调用的逻辑。

  2. 绝对禁止阻塞

    在 Suspend 和 Resume 之间,绝对不能调用任何会引起阻塞的 FreeRTOS API(如 vTaskDelay、xQueueReceive 等等待数据的函数)。

    • 原因:如果要阻塞,系统必须切换到别的任务。但调度器被你暂停了,切换不了,于是系统就会卡死在这里。

  3. 防御不了中断

    • 如果你的临界资源(比如一个全局变量),既被任务 A 访问,也被串口中断 ISR 访问。

    • 那么使用 vTaskSuspendAll无效的。因为 ISR 依然会打断任务 A,导致数据竞争。

    • 在这种情况下,你必须使用屏蔽中断taskENTER_CRITICAL)。

5. 三种保护机制对比总结

方法谁能打断我?谁会被挡住?适用场景代价
互斥量 (Mutex)高优先级任务、中断其他想拿锁的任务任务间竞争,持有时间较长任务可能会阻塞等待
暂停调度器中断所有其他任务任务间竞争,逻辑稍长,不想关中断实时性降低(高优先级任务无法抢占)
屏蔽中断高于阈值的超级中断所有任务 + 低优先级中断任务与中断竞争,或极短的原子操作响应最快,但对系统中断响应有影响

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值