【FreeRTOS任务调度机制学习】

1、通过就绪态(ready)、阻塞态链表(delay)、挂起态链表(suspend)进行任务调度。

链表定义

/* 就绪、阻塞、挂起任务链表. --------------------*/
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ] = {0};	/*< Prioritised ready tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList1 = {0};								/*< Delayed tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList2 = {0};								/*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
PRIVILEGED_DATA static List_t xPendingReadyList = {0};								/*< Tasks that have been readied while the scheduler was suspended.  They will be moved to the ready list when the scheduler is resumed. */

1、当优先级相同(优先级大于0)的任务创建时,先执行最后一个创建的任务,然后再执行第一个创建的任务。(如果优先级都为0,则先执行空闲任务,然后执行第一个创建的任务);完成任务创建后OS进行同等优先级任务轮流执行(空闲任务礼让一次,让其它任务先运行一个tick)。
2、示例

xTaskCreate(vTask1,"Task1",100,NULL,0,NULL);
xTaskCreate(vTask2,"Task1",100,NULL,0,NULL);
xTaskCreate(vTask3,"Task1",100,NULL,0,NULL);
xTaskCreate(IDEL_task,"Idle",100,NULL,0,NULL); //空闲任务

在任务优先级同为0的pxReadyTaskList[4] 链表中

pxReadyTaskList[0]  = task1;
pxReadyTaskList[1]  = task2;
pxReadyTaskList[2]  = task3;
pxReadyTaskList[3]  = Idle task;

则执行顺序为

TCB -> pxReadyTaskList[3];
TCB -> pxReadyTaskList[0];
TCB -> pxReadyTaskList[1];
TCB -> pxReadyTaskList[2];

2、TCB控制块结构体描述

typedef struct tskTaskControlBlock
{
	volatile StackType_t	*pxTopOfStack;	/*< 指向任务堆栈中最后一项的位置。这必须是TCB结构体的第一个成员。 */

	ListItem_t			xStateListItem;	/*< 任务的状态列表项引用的列表表示该任务的状态(就绪、阻塞、挂起). */
	ListItem_t			xEventListItem;		/*< 用于从事件列表中引用任务. */
	UBaseType_t			uxPriority;			/*< 任务的优先级。0为最低优先级. */
	StackType_t			*pxStack;			/*<指向堆栈的起点. */
	char				pcTaskName[ configMAX_TASK_NAME_LEN ];/*< 创建时给任务的描述性名称.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */


} tskTCB;

3、向就绪态任务链表增加任务

就绪态链表结构体

/*
 * Place the task represented by pxTCB into the appropriate ready list for
 * the task.  It is inserted at the end of the list.
 */
#define prvAddTaskToReadyList( pxTCB )																\
	traceMOVED_TASK_TO_READY_STATE( pxTCB );														\
	taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );												\
	vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
	tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
/*-----------------------------------------------------------*/
// Place the task represented by pxTCB into the appropriate ready list for the task.  It is inserted at the end of the list
#define prvAddTaskToReadyList( pxTCB )																\
		traceMOVED_TASK_TO_READY_STATE( pxTCB );														\
		taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );												\
		vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ]),	 &( ( pxTCB )->xStateListItem ) ); \
		tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
		
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
	/* Ensure interrupts don't access the task lists while the lists are being
	updated. */
	taskENTER_CRITICAL();
	{
		uxCurrentNumberOfTasks++;
		if( pxCurrentTCB == NULL )
		{
			/* 没有其他任务,或者所有其他任务都在
挂起状态——将其作为当前任务 */
			pxCurrentTCB = pxNewTCB;

			if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
			{
				/* 这是要创建的第一个任务,因此需要进行初步初始化。
如果调用失败,我们将无法恢复,但我们将报告失败. */
				prvInitialiseTaskLists();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			/* 如果调度器尚未运行,如果该任务是迄今要创建的最高
优先级任务,则将其设置为当前任务. */
			if( xSchedulerRunning == pdFALSE )
			{
				if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
				{
					pxCurrentTCB = pxNewTCB;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}

		uxTaskNumber++;

		#if ( configUSE_TRACE_FACILITY == 1 )
		{
			/* 在TCB中添加计数器仅用于跟踪. */
			pxNewTCB->uxTCBNumber = uxTaskNumber;
		}
		#endif /* configUSE_TRACE_FACILITY */
		traceTASK_CREATE( pxNewTCB );

		prvAddTaskToReadyList( pxNewTCB );

		portSETUP_TCB( pxNewTCB );
	}
	taskEXIT_CRITICAL();

	if( xSchedulerRunning != pdFALSE )
	{
		/*如果创建的任务的优先级高于当前任务,高优先级任务先运行. */
		if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
		{
			taskYIELD_IF_USING_PREEMPTION();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

4、向阻塞态任务链表增加任务

阻塞态链表结构体

/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
count overflows. */
#define taskSWITCH_DELAYED_LISTS()																	\
{																									\
	List_t *pxTemp;																					\
																									\
	/* The delayed tasks list should be empty when the lists are switched. */						\
	configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );										\
																									\
	pxTemp = pxDelayedTaskList;																		\
	pxDelayedTaskList = pxOverflowDelayedTaskList;													\
	pxOverflowDelayedTaskList = pxTemp;																\
	xNumOfOverflows++;																				\
	prvResetNextTaskUnblockTime();																	\
}
static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
{
TickType_t xTimeToWake;
const TickType_t xConstTickCount = xTickCount;

	#if( INCLUDE_xTaskAbortDelay == 1 )
	{
		/* About to enter a delayed list, so ensure the ucDelayAborted flag is
		reset to pdFALSE so it can be detected as having been set to pdTRUE
		when the task leaves the Blocked state. */
		pxCurrentTCB->ucDelayAborted = pdFALSE;
	}
	#endif

	/* 在将任务添加到阻止列表之前,将其从就绪列表中删除
			因为两个列表使用相同的列表项 */
	if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
	{
		/* 当前任务必须在就绪列表中,因此不需要
			检查后,可以直接调用端口重置宏. */
		portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	#if ( INCLUDE_vTaskSuspend == 1 )
	{
		if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
		{
			/* 将任务添加到挂起任务列表,而不是延迟任务
			列表,以确保它不会被定时事件唤醒。它会无限期地阻塞. */
			vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
		}
		else
		{
			/*如果事件发生,计算任务应该被唤醒的时间
			不会发生。这可能会溢出,但没关系内核将正确地管理它. 
			*/
			xTimeToWake = xConstTickCount + xTicksToWait;

			/* The list item will be inserted in wake time order. */
			listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

			if( xTimeToWake < xConstTickCount )
			{
				/* Wake time has overflowed.  Place this item in the overflow
				list. */
				vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
			}
			else
			{
				/* The wake time has not overflowed, so the current block list
				is used. */
				vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

				/* If the task entering the blocked state was placed at the
				head of the list of blocked tasks then xNextTaskUnblockTime
				needs to be updated too. */
				if( xTimeToWake < xNextTaskUnblockTime )
				{
					xNextTaskUnblockTime = xTimeToWake;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
	}
	#else /* INCLUDE_vTaskSuspend */
	{
		/* Calculate the time at which the task should be woken if the event
		does not occur.  This may overflow but this doesn't matter, the kernel
		will manage it correctly. */
		xTimeToWake = xConstTickCount + xTicksToWait;

		/* The list item will be inserted in wake time order. */
		listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );

		if( xTimeToWake < xConstTickCount )
		{
			/* Wake time has overflowed.  Place this item in the overflow list. */
			vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
		}
		else
		{
			/* The wake time has not overflowed, so the current block list is used. */
			vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );

			/* If the task entering the blocked state was placed at the head of the
			list of blocked tasks then xNextTaskUnblockTime needs to be updated
			too. */
			if( xTimeToWake < xNextTaskUnblockTime )
			{
				xNextTaskUnblockTime = xTimeToWake;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}

		/* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */
		( void ) xCanBlockIndefinitely;
	}
	#endif /* INCLUDE_vTaskSuspend */
}

相关推荐

  1. FreeRTOS任务调度机制学习

    2024-03-11 09:54:01       22 阅读
  2. FreeRTOS学习 -- 任务 API 函数

    2024-03-11 09:54:01       11 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-11 09:54:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-11 09:54:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-11 09:54:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-11 09:54:01       20 阅读

热门阅读

  1. 归并排序

    2024-03-11 09:54:01       18 阅读
  2. 微信小程序-wxml语法

    2024-03-11 09:54:01       22 阅读
  3. Keepalived工具的基本介绍(原理:VRRP协议)

    2024-03-11 09:54:01       21 阅读
  4. MongoDB聚合运算符:$dayOfYear

    2024-03-11 09:54:01       23 阅读
  5. selenium启用MS Edge浏览器/下载MS Edge WebDriver

    2024-03-11 09:54:01       20 阅读
  6. 嵌入式开发的3种架构

    2024-03-11 09:54:01       20 阅读