概要

vTaskSuspendAll() 是 FreeRTOS 中的一个重要函数,用于挂起任务调度器。下面从源码角度详细解析这个函数。

函数功能

vTaskSuspendAll() 的主要作用是挂起任务调度器,但它不会禁用中断。在调度器挂起期间:

  1. 不会发生任务切换
  2. 可以安全地访问共享资源(无需额外互斥锁)
  3. 中断服务程序仍然可以执行

源码解析

  1. 函数定义
/* 在 task.c 中 */
void vTaskSuspendAll( void )
{
    /* 增加调度器挂起计数 */
    ++uxSchedulerSuspended;
}
  1. 关键数据结构
/* 在 task.c 中声明的全局变量 */
#if ( INCLUDE_xTaskGetSchedulerState == 1 )
    /* 调度器挂起计数器 */
    volatile BaseType_t uxSchedulerSuspended = ( BaseType_t ) pdFALSE;
#else
    /* 很多编译器会对没有引用的静态变量发出警告 */
    static volatile BaseType_t uxSchedulerSuspended = ( BaseType_t ) pdFALSE;
#endif
  1. 工作原理
    调度器挂起计数器
    1)uxSchedulerSuspended 是一个计数器(不是简单的布尔值)
    2)值为 0 表示调度器正常运行
    3)值大于 0 表示调度器被挂起
    4)使用计数器而不是布尔值,允许函数嵌套调用
    相关函数调用
/* 挂起调度器 */
vTaskSuspendAll();

/* 执行临界区操作(无任务切换) */
// ... 你的代码 ...

/* 恢复调度器 */
xTaskResumeAll();
  1. 如何阻止任务切换
    调度器的挂起主要通过影响以下地方来实现:
    1) 在 xTaskIncrementTick() 中:
BaseType_t xTaskIncrementTick( void )
{
    /* ... 前面的代码 ... */
    
    if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
    {
        /* 只有在调度器未挂起时才检查任务切换 */
        if( xYieldPending != pdFALSE )
        {
            xSwitchRequired = pdTRUE;
        }
    }
    
    /* ... 后面的代码 ... */
}

2) 在 xTaskResumeAll() 中(恢复函数):

BaseType_t xTaskResumeAll( void )
{
    /* 减少挂起计数 */
    --uxSchedulerSuspended;
    
    if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
    {
        /* 如果计数为0,可能需要处理累积的tick */
        /* 并检查是否需要任务切换 */
        if( xPendedTicks > ( TickType_t ) 0U )
        {
            /* 处理挂起期间积累的tick */
        }
        
        /* 检查是否需要任务切换 */
        if( xYieldPending != pdFALSE )
        {
            xSwitchRequired = pdTRUE;
        }
    }
}
  1. 注意事项
    1)不可递归:虽然使用计数器支持嵌套,但需确保每个 vTaskSuspendAll() 都有对应的 xTaskResumeAll()
    2)中断处理:
    中断仍然会发生
    中断服务程序可以调用 FreeRTOS API
    但不会发生任务切换,直到调度器恢复
    3)时间管理:
    在调度器挂起期间,系统 tick 中断仍然发生
    tick 计数会被累积,在恢复时处理
  2. 性能考虑
    1)vTaskSuspendAll() 执行非常快(只是增加计数器)
    2)比使用互斥锁开销小
    3)适合保护较长的临界区代码
    4)不适合需要中断同步的场景(此时应用 taskENTER_CRITICAL())

总结

vTaskSuspendAll() 是一个轻量级的调度器挂起机制,通过简单的计数器管理来实现。它提供了在不需要任务切换的场景下安全访问共享资源的能力,同时保持了中断响应的能力。使用时需要注意正确的嵌套和恢复,以避免系统死锁或性能问题。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐