FreeRTOS
作者:解琛
时间:2020 年 8 月 19 日
五、多优先级
在 FreeRTOS 中,数字优先级越小,逻辑优先级也越小,这与 RT-Thread 和 μC/OS 刚好相反。

就绪列表 pxReadyTasksLists[ configMAX_PRIORITIES ] 是一个数组,数组里面存的是就绪任务的 TCB (准确来说是 TCB 里面的 xStateListItem 节点)。
数组的下标对应任务的优先级,优先级越低对应的数组下标越小。空闲任务的优先级最低,对应的是下标为 0 的链表。
空闲任务自系统启动后会一直就绪,因为系统至少得保证有一个任务可以运行。
任务在创建的时候,会根据任务的优先级将任务插入到就绪列表不同的位置。
相同优先级的任务插入到就绪列表里面的同一条链表中。
pxCurrenTCB 是一个全局的 TCB 指针,用于指向优先级最高的就绪任务的 TCB,即当前正在运行的 TCB 。
要想让任务支持优先级,即只要解决在任务切换 (taskYIELD) 的时候,让 pxCurrenTCB 指向最高优先级的就绪任务的 TCB 就可以。
FreeRTOS 提供了两种寻找就绪列表中最高优先级的方法,一种是通用的,一种是根据特定的处理器优化过的。
5.1 查找最高优先级的就绪任务
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
查找最高优先级的就绪任务的两种方法具体由 configUSE_PORT_OPTIMISED_TASK_SELECTION 这个宏控制,定义为 0 选择通用方法,定义为 1 选择根据处理器优化的方法。
该宏默认在 portmacro.h 中定义为 1,即使用优化过的方法。
5.1.1 通用方法
5.1.1.1 taskRECORD_READY_PRIORITY()
/* 空闲任务优先级宏定义,在 task.h 中定义 */
#define tskIDLE_PRIORITY ( ( UBaseType_t ) 0U )
/* 定义 uxTopReadyPriority,在 task.c 中定义 */
static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
taskRECORD_READY_PRIORITY() 用于更新 uxTopReadyPriority 的值。
uxTopReadyPriority 是一个在 task.c 中定义的静态变量,用于表示创建的任务的最高优先级,默认初始化为 0,即空闲任务的优先级。
/* 查找最高优先级的就绪任务:通用方法 */
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
/* uxTopReadyPriority 存的是就绪任务的最高优先级; */
#define taskRECORD_READY_PRIORITY( uxPriority ) \
{ \
if( ( uxPriority ) > uxTopReadyPriority ) \
{ \
uxTopReadyPriority = ( uxPriority ) \
} \
} /* taskRECORD_READY_PRIORITY */
#endif
5.1.1.2 taskSELECT_HIGHEST_PRIORITY_TASK()
taskSELECT_HIGHEST_PRIORITY_TASK() 用于寻找优先级最高的就绪任务,实质就是更新 uxTopReadyPriority 和 pxCurrentTCB 的值。
/* 查找最高优先级的就绪任务:通用方法 */
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority = uxTopReadyPriority; \
\
/* 寻找包含就绪任务的最高优先级的队列 */ \
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \
{
\
--uxTopPriority; \
} \
\
/* 获取优先级最高的就绪任务的 TCB,然后更新到 pxCurrentTCB; */ \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
/* 更新 uxTopReadyPriority; */ \
uxTopReadyPriority = uxTopPriority; \
} /* taskSELECT_HIGHEST_PRIORITY_TASK */
#endif
5.1.2 优化方法

优化的方法的出现,这得益于 Cortex-M 内核有一个计算前导零的指令 CLZ,所谓前导零就是计算一个变量 (Cortex-M 内核单片机的变量为 32 位) 从高位开始第一次出现 1 的位的前面的零的个数。
uxTopReadyPriority 的每个位号对应的是任务的优先级,任务就绪时,则将对应的位置 1,反之则清零。
利用前导零计算指令可以很快计算出就绪任务中的最高优先级为:
( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) ) = ( 31UL - ( uint32_t )6 ) = 25。
5.1.2.1 taskRECORD_READY_PRIORITY()
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) \
( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define taskRECORD_READY_PRIORITY( uxPriority ) \
portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
taskRECORD_READY_PRIORITY() 用于根据传进来的形参(通常形参就是任务的优先级)将变量 uxTopReadyPriority 的某个位置 1。
5.1.2.2 taskRESET_READY_PRIORITY()
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities )\
( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
#define taskRESET_READY_PRIORITY( uxPriority )
portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
taskRECORD_READY_PRIORITY() 用于根据传进来的形参(通常形参就是任务的优先级)将变量 uxTopReadyPriority 的某个位清 0。
实际上根据优先级调用 taskRESET_READY_PRIORITY() 函数复位 uxTopReadyPriority 变量中对应的位时,要先确保就绪列表中对应该优先级下的链表没有任务才行。
也就是说,将任务优先级在变量 uxTopReadyPriority 中对应的位清零,还需要将任务从就绪列表删除。
5.1.2.3 taskSELECT_HIGHEST_PRIORITY_TASK()
taskSELECT_HIGHEST_PRIORITY_TASK() 用于寻找优先级最高的就绪任务,实质就是更新 uxTopReadyPriority 和 pxCurrentTCB 的值。
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) \
uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority; \
\
/* 寻找最高优先级 */ \
portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
/* 获取优先级最高的就绪任务的TCB,然后更新到pxCurrentTCB */ \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ]

最低0.47元/天 解锁文章
7734

被折叠的 条评论
为什么被折叠?



