Skip to content

支持任务多优先级

找到最高优先级的任务的任务块

c
/*
*************************************************************************
*                               宏定义
*************************************************************************
*/

/* 将任务添加到就绪列表 */                                    
#define prvAddTaskToReadyList( pxTCB )																   \
	taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );												   \
	vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \


/* 查找最高优先级的就绪任务:通用方法 */                                    
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
	/* uxTopReadyPriority 存的是就绪任务的最高优先级 */
	#define taskRECORD_READY_PRIORITY( uxPriority )														\
	{																									\
		if( ( uxPriority ) > uxTopReadyPriority )														\
		{																								\
			uxTopReadyPriority = ( uxPriority );														\
		}																								\
	} /* taskRECORD_READY_PRIORITY */

	/*-----------------------------------------------------------*/

	#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 */

	/*-----------------------------------------------------------*/

	/* 这两个宏定义只有在选择优化方法时才用,这里定义为空 */
	#define taskRESET_READY_PRIORITY( uxPriority )
	#define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
    
/* 查找最高优先级的就绪任务:根据处理器架构优化后的方法 */
#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

	#define taskRECORD_READY_PRIORITY( uxPriority )	portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )

	/*-----------------------------------------------------------*/

	#define taskSELECT_HIGHEST_PRIORITY_TASK()														    \
	{																								    \
	UBaseType_t uxTopPriority;																		    \
																									    \
		/* 寻找最高优先级 */								                            \
		portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );								    \
		/* 获取优先级最高的就绪任务的TCB,然后更新到pxCurrentTCB */                                       \
		listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );		    \
	} /* taskSELECT_HIGHEST_PRIORITY_TASK() */

	/*-----------------------------------------------------------*/
#if 0
	#define taskRESET_READY_PRIORITY( uxPriority )														\
	{																									\
		if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 )	\
		{																								\
			portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );							\
		}																								\
	}
#else
    #define taskRESET_READY_PRIORITY( uxPriority )											            \
    {																							        \
            portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );					        \
    }
#endif
    
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

添加一个新的任务到优先级队列之中

没有优化

taskRECORD_READY_PRIORITY( uxPriority )在当前优先级保存现在的优先级

taskSELECT_HIGHEST_PRIORITY_TASK()寻找最高优先级

优化方法: 有一个指令CLZ, 会返回一个数字最高的出现1前面的0的个数

taskRECORD_READY_PRIORITY( uxPriority )把当前优先级某一个位设置为1

taskSELECT_HIGHEST_PRIORITY_TASK()寻找最高优先级

taskRESET_READY_PRIORITY( uxPriority )清零某一个位

c
//设置在添加任务的时候是否使用优化
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
	#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1

	/* 检测优先级配置 */
	#if( configMAX_PRIORITIES > 32 )
		#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32.  It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
	#endif

	/* 根据优先级设置/清除优先级位图中相应的位 */
	#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
	#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )

	/*-----------------------------------------------------------*/

	#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )

#endif /* taskRECORD_READY_PRIORITY */

使用优化方法时候的宏定义, 实际上就是31减去clz指令获得的数字, 得到第几位是1

  • 修改任务控制块, 添加优先级变量
c
{
	//栈顶
	volatile StackType_t	*pxTopOfStack;		
	
	//任务节点
	ListItem_t				xStateListItem;	
	StackType_t 			*pxStack; 		//任务栈的起始位置
	
	char 					pcTaskName[configMAX_TASK_NAME_LEN];
	
	TickType_t xTicksToDelay; /* 用于延时 */  
		//优先级
    UBaseType_t			uxPriority;    

}tskTCB;
  • 创建任务的时候传进去优先级
c
prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters,uxPriority, &xReturn, pxNewTCB);
c
    /* 初始化优先级 */
	if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
	{
		uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
	}
	pxNewTCB->uxPriority = uxPriority;

大于最大优先级, 就设置为最大优先级

  • 实现自动添加到列表
c
/* 将任务添加到就绪列表 */
prvAddNewTaskToReadyList( pxNewTCB );
c
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
	/* 进入临界段 */
	taskENTER_CRITICAL();
	{
		/* 全局任务计时器加一操作 */
        uxCurrentNumberOfTasks++;
        
        /* 如果pxCurrentTCB为空,则将pxCurrentTCB指向新创建的任务 */
		if( pxCurrentTCB == NULL )
		{
			pxCurrentTCB = pxNewTCB;

			/* 如果是第一次创建任务,则需要初始化任务相关的列表 */
            if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
			{
				/* 初始化任务相关的列表 */
                prvInitialiseTaskLists();
			}
		}
		else /* 如果pxCurrentTCB不为空,则根据任务的优先级将pxCurrentTCB指向最高优先级任务的TCB */
		{
				if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
				{
					pxCurrentTCB = pxNewTCB;
				}
		}
		uxTaskNumber++;
        
		/* 将任务添加到就绪列表 */
        prvAddTaskToReadyList( pxNewTCB );

	}
	/* 退出临界段 */
	taskEXIT_CRITICAL();
}

这一次创建任务的时候会自动修改当前的任务, 以及添加链表

还需要修改开启任务调度的函数

  • 修改Delay函数
c
    /* 将任务从就绪列表移除 */
    //uxListRemove( &( pxTCB->xStateListItem ) );
    taskRESET_READY_PRIORITY( pxTCB->uxPriority );

暂时不能移除, 但是需要标志位清零, 因为现在通过扫描列表来实现延迟

  • 修改修改任务的函数
c
void vTaskSwitchContext( void )
{
	/* 获取优先级最高的就绪任务的TCB,然后更新到pxCurrentTCB */
    taskSELECT_HIGHEST_PRIORITY_TASK();
}
  • 计时器调用函数
c
/* 延时时间到,将任务就绪 */
if( pxTCB->xTicksToDelay ==0 )
{
    taskRECORD_READY_PRIORITY( pxTCB->uxPriority );
}

总结

在创建函数的时候会把自身优先级设置为1

在调用delay函数之后会清除自身优先级, 然后进行函数切换

在时钟每次中断的时候会进行任务切换, 选择优先级最高的函数

切换函数的时候会调用xPortPendSVHandler函数, 在这个函数中会更新TCB然后更换函数

这里实现的每个优先级只能有一个函数

实际的FreeRTOS

c
#define taskSELECT_HIGHEST_PRIORITY_TASK()									\
	{																	\
	UBaseType_t uxTopPriority;											   \
																		\
		/* Find the highest priority list that contains ready tasks. */		  \ 
         portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );	   \
         configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 );\
         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );\
} /* taskSELECT_HIGHEST_PRIORITY_TASK() */
c
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )								   \
{																				  \
List_t * const pxConstList = ( pxList );											 \
	/* Increment the index to the next item and return the item, ensuring */			\
	/* we don't return the marker used at the end of the list.  */					   \
	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;					   \
	if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	\
	{																				\
		( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;					 \
	}																				\
	( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;										\
}

这一个宏定义会把首位的链表改为下一个链表