五、FreeRTOS 多优先级

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

解琛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值