1. 空闲任务相关API函数

函数 描述
portTASK_FUNCTION() 宏定义,真正函数原型为void prvIdleTask(void * pvParameters)

任务挂起中其它重要的API函数(介绍过的函数不列出,请参考前面的文章):

函数 描述
prvCheckTasksWaitingTermination() 回收等待列表xTasksWaitingTermination中任务的堆栈和任务控制块内存
vApplicationIdleHook() 任务钩子函数,由用户提供
prvGetExpectedIdleTime() 获取下一个唤醒任务的时钟节拍数,即获取了处理器进入低功耗模式的时长

2. 空闲任务基本概念

在RTOS调度器开启后,为了确保至少有一个任务执行,FreeRTOS中会在开启调度器时自动创建空闲任务。

动态方式创建任务:

//动态方式创建空闲任务
xReturn = xTaskCreate( prvIdleTask,"IDLE", configMINIMAL_STACK_SIZE,( void * ) NULL,( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),&xIdleTaskHandle );

如果使用静态方式创建任务,需要用户自己定义空闲任务所需要的内存空间,如下:

//空闲任务
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
static StaticTask_t IdleTaskTCB;//空闲任务所需内存
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{*ppxIdleTaskTCBBuffer=&IdleTaskTCB;*ppxIdleTaskStackBuffer=IdleTaskStack;*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}
//静态方式创建
xIdleTaskHandle = xTaskCreateStatic(prvIdleTask,"IDLE",ulIdleTaskStackSize,( void * ) NULL,( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),pxIdleTaskStackBuffer,pxIdleTaskTCBBuffer );

说明:

  • 如果一个任务删除自己,则任务先放入列表xTasksWaitingTermination,等到空闲任务时再回收堆栈和TCB内存。
  • 低功耗目的尽量使MCU在空闲状态时处于低功耗模式。
  • 空闲任务的优先级一般是最低的,设置优先级为0。如果有任务与空闲任务优先级相同,并且宏configIDLE_SHOULD_YIELD设置为1,则空闲任务直接让出CPU资源给其它任务。

3. 空闲任务函数portTASK_FUNCTION()

3.1 函数portTASK_FUNCTION()分析

该函数原型如下:

static portTASK_FUNCTION( prvIdleTask, pvParameters )

它是一个宏定义,如下:

#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )

即函数原型为:void prvIdleTask(void * pvParameters)

函数源代码如下:

static portTASK_FUNCTION( prvIdleTask, pvParameters )
{/* 防止编译器警告 */( void ) pvParameters;for( ;; ){/* 检查是否有任务删除本身(即自己删除自己),如果有释放控制块和堆栈内存 */prvCheckTasksWaitingTermination();/* 如果使用抢占式内核 */#if ( configUSE_PREEMPTION == 0 ){taskYIELD();  /* 执行一次任务切换 */}#endif /* configUSE_PREEMPTION *//* * 相同优先级的任务会使用时间片方式获取CPU资源* 如果设置configUSE_PREEMPTION 为1,即使用抢占式内核* 同时,设置configIDLE_SHOULD_YIELD 为1,则与空闲任务优先级相同,空闲任务放弃CPU使用权给其它任务*/#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ){/* 如果空闲任务优先级下有多个任务 */if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 ){taskYIELD();   /* 执行任务切换,将CPU资源给其它任务 */}else{mtCOVERAGE_TEST_MARKER();}}#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) *//* 如果使能空闲任务钩子函数,需要用户提供,这样用户不增加任务开销的情况下实现后台功能,如设置CPU进入省电模式 */#if ( configUSE_IDLE_HOOK == 1 ){extern void vApplicationIdleHook( void );/* 这个函数中绝对不允许调用可能引起阻塞任务的函数 */vApplicationIdleHook(); }#endif /* configUSE_IDLE_HOOK *//* 如果使能了低功耗Tickless模式功能 */#if ( configUSE_TICKLESS_IDLE != 0 ){TickType_t xExpectedIdleTime;/** 执行两次同样的比较(xExpectedIdleTime和configEXPECTED_IDLE_TIME_BEFORE_SLEEP)* 第一次比较是测试一下是否达到预期的空闲时间,避免每次执行空闲任务都挂起调度器,然后再解除调度器*/xExpectedIdleTime = prvGetExpectedIdleTime();if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ){vTaskSuspendAll();  /* 挂起调度器 */{configASSERT( xNextTaskUnblockTime >= xTickCount );/* 再次测试一下是否达到预期的空闲时间 */xExpectedIdleTime = prvGetExpectedIdleTime();if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ){traceLOW_POWER_IDLE_BEGIN();/* * 调用宏,进入低功耗模式,和如何退出低功耗模式* 系统时间补偿* 根据MCU功耗模式编写的代码,由移植层提供*/portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );    traceLOW_POWER_IDLE_END();}else{mtCOVERAGE_TEST_MARKER();}}( void ) xTaskResumeAll();   /* 恢复调度器 */}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_TICKLESS_IDLE */}
}

3.2 函数prvCheckTasksWaitingTermination()

该函数主要功能是回收等待列表xTasksWaitingTermination中任务的堆栈和任务控制块内存。当任务删除本身时(即自己删除自己),由于任务可能没执行完,不能立即释放内存空间,就先放入该列表,等到空闲任务时再删除。

函数源代码如下:

static void prvCheckTasksWaitingTermination( void )
{/* 如果使能了任务删除功能 */#if ( INCLUDE_vTaskDelete == 1 ){BaseType_t xListIsEmpty;/* 等待删除列表中删除的任务大于0,即有需要删除的任务 */while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U ){vTaskSuspendAll(); /* 调度锁开启 */{/* 列表xTasksWaitingTermination列表项的数量不为0,返回pdFALSE  */xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );}( void ) xTaskResumeAll();   /* 调度锁关闭 *//* 如果列表xTasksWaitingTermination有需要删除的任务 */if( xListIsEmpty == pdFALSE ){TCB_t *pxTCB;taskENTER_CRITICAL(); /* 进入临界区 */{/* 获取列表xTasksWaitingTermination第一个列表项,即第一个需要删除的任务 */pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );/* 将任务从列表xTasksWaitingTermination移除 */( void ) uxListRemove( &( pxTCB->xStateListItem ) );  --uxCurrentNumberOfTasks;       /* 当前系统总任务数减1 */--uxDeletedTasksWaitingCleanUp; /* 列表xTasksWaitingTermination需要删除的任务数减1 */}taskEXIT_CRITICAL(); /* 退出临界区 */prvDeleteTCB( pxTCB );               /* 根据任务堆栈和控制块申请内存的方式,释放任务的堆栈和控制块内存 */}else{mtCOVERAGE_TEST_MARKER();}}}#endif /* INCLUDE_vTaskDelete */
}

3.3 函数prvGetExpectedIdleTime()

如果此时无其它任务执行,只有空闲任务在执行,将返回下一个唤醒任务的时钟节拍数,相当于获取了处理器进入低功耗模式的时长。

函数原型如下:

/********************************************************
参数:无
返回:TickType_t:返回下一个唤醒任务的时钟节拍数
*********************************************************/
static TickType_t prvGetExpectedIdleTime( void )

函数源代码如下:

static TickType_t prvGetExpectedIdleTime( void )
{TickType_t xReturn;UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;/* 选择下一个要执行的任务,0:通用方法,1:特殊方法,系统架构提供 */#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ){if( uxTopReadyPriority > tskIDLE_PRIORITY ){uxHigherPriorityReadyTasks = pdTRUE;}}#else{/* 特殊方式选择下一个执行的任务,每一位表示一个优先级 */const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01;if( uxTopReadyPriority > uxLeastSignificantBit ){uxHigherPriorityReadyTasks = pdTRUE;}}#endif/* 如果当前优先级大于空闲任务优先级 */if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ){xReturn = 0;}/* 空闲任务优先级下,不止空闲任务一个优先级 */else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ){xReturn = 0;}/* 有更高优先级任务就绪 */else if( uxHigherPriorityReadyTasks != pdFALSE )    {xReturn = 0;}/* 空闲任务优先级最高 */else{xReturn = xNextTaskUnblockTime - xTickCount;    /* 计算下一个唤醒任务的时间节拍 */}return xReturn;
}

FreeRTOS原理剖析:空闲任务分析相关推荐

  1. 原理剖析(第 013 篇)应用系统性能调优

    原理剖析(第 013 篇)应用系统性能调优 - 一.大致介绍 1. 本人接手的一个打车系统,因为出现了一次响应十分缓慢的情况,因此才有了应用调优的篇章: 2.由于过程中可能没有阐述的太清楚,如想详细了 ...

  2. react16常见api以及原理剖析

    Vue 与 React 两个框架的粗略区别对比 Vue 的优势包括: 模板和渲染函数的弹性选择 简单的语法及项目创建 更快的渲染速度和更小的体积 React 的优势包括: 更适用于大型应用和更好的可测 ...

  3. React16常用api解析以及原理剖析

    React16常用api解析以及原理剖析 目录 Vue 与 React 两个框架的粗略区别对比 react 16 版本常见 api react 生命周期 react 事件机制 react.Compon ...

  4. Hystrix和Sentinel以及Sentinel原理剖析

    目录 目录 Hystrix Hystrix介绍 Hystrix的作用 流程: 服务降级 服务熔断 Sentinel 流控规则 流量控制规则 (FlowRule) 阈值类型讲解 降级规则(熔断没有半开) ...

  5. java架构学习——5. 线程池原理剖析锁的深度化

    本篇博文主要包含: 线程池的基本概念 ThreadPoolExecutor 线程池四种创建方式 -newCachedThreadPool:可缓存线程池 -newFixedThreadPool:定长线程 ...

  6. socket之send和recv原理剖析

    socket之send和recv原理剖析 1. 认识TCP socket的发送和接收缓冲区 当创建一个TCP socket对象的时候会有一个发送缓冲区和一个接收缓冲区,这个发送和接收缓冲区指的就是内存 ...

  7. fastText的原理剖析

    fastText的原理剖析 1. fastText的模型架构 fastText的架构非常简单,有三层:输入层.隐含层.输出层(Hierarchical Softmax) 输入层:是对文档embeddi ...

  8. lua游戏脚本实例源码_Lua与其他宿主语言交互原理剖析

    Lua与其他宿主语言交互原理剖析 题外话:今天周末,刚好在家有时间就把我这次项目组内部分享的文章贴出来,分享给大家,同时也方便以后自己翻阅. 一. Lua简介 目标:Lua语言本身是用C语言来编写开发 ...

  9. Go语言底层原理剖析

    作者:郑建勋 出版社:电子工业出版社 品牌:博文视点 出版时间:2021-08-01 Go语言底层原理剖析

最新文章

  1. 条件注解 @ConditionalOnBean 的正确使用姿势
  2. snmp Oid整理与运用
  3. 中文与Unicode码互转(utf-8)
  4. linux调试crontab,linux - crontab 的调试,启动thin服务器
  5. Head First summary
  6. 视觉错觉模型_极具视觉爆发力的影院设计
  7. HDU.1003 Max Sum
  8. Linux内核探索之路——关于方法
  9. 30岁,我从前端转型管理成功了
  10. vmos模拟的机型_VMOS(虚拟大师)
  11. DBUtils详细介绍+实例
  12. 6. 单例模式有几种写法?
  13. 补丁冷启动模式_试验模式补丁说明
  14. java去掉转义字符,双引号,全角空格
  15. java实现分页功能(一)
  16. 求阶乘问题c语言编程,求阶乘问题
  17. Spring WebFlux运用中的思考与对比
  18. python 自动填表单 不用webdriver_用python-webdriver实现自动填表
  19. ArcGIS水文分析提取河网及流域
  20. GhostnetV1(2020)

热门文章

  1. 关于@Value读不到配置文件内容的问题
  2. DL在地球物理中的应用及发展趋势
  3. NS10.1 产品技术规范
  4. css实现旋转的小流星动画
  5. 如何获客:3招做好触客营销实现高效获
  6. 基于stm32人体健康监测系统
  7. Sass的概念以及命令
  8. 如何使用python下载B站视频
  9. Js逆向教程-10常见代码混淆
  10. 实体、协议、服务和服务访问点的概念