FreeRTOS支持时间片

什么是时间片

时间片就是同一个优先级下可以有多个任务,每个任务轮流地享有相同的 CPU 时间, 享有 CPU 的时间我们叫时间片。在 RTOS 中,最小的时间单位为一个 tick,即 SysTick 的中断周期,与其说 FreeRTOS 支持时间片,倒不如说它的时间片就是正常的任务调度。

时间片实现关键

时间片实现关键在
taskRESET_READY_PRIORITY()taskSELECT_HIGHEST_PRIORITY_TASK()
这两个函函数。

taskSELECT_HIGHEST_PRIORITY_TASK()

系统在任务切换的时候总会从就绪列表中寻找优先级最高的任务来执行,寻找优先级
最高的任务这个功能由 taskSELECT_HIGHEST_PRIORITY_TASK()函数来实现,该函数在
task.c 中定义,如下

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

先寻找就绪任务的最高优先级。即根据优先级位图表uxTopReadyPriority 找到就绪任务的最高优先级,然后将优先级暂存在uxTopPriority
获取优先级最高的就绪任务的 TCB,然后更新到 pxCurrentTCB。这里关键在更新到pxCurrentTCB的宏listGET_OWNER_OF_NEXT_ENTRY,如下

 #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )\
 {\
 List_t * const pxConstList = ( pxList );\
 /* 节点索引指向链表第一个节点调整节点索引指针,指向下一个节点,
 如果当前链表有 N 个节点,当第 N 次调用该函数时, pxIndex 则指向第 N 个节点 */\
 ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;\
 /* 当遍历完链表后, pxIndex 回指到根节点 */\
 if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )\
 {\
 ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;\
 }\
 /* 获取节点的 OWNER,即 TCB */\
 ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;\
 }

关键在下面这句,下面看图比较好说明

( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;

在这里插入图片描述
对于优先级2,当第一次执行listGET_OWNER_OF_NEXT_ENTRY后,pxIndex指向Task1TCB->xStateListItem,所以pvOwner取到的是Task1TCB赋值给pxCurrentTCB.

对于优先级2,当第二次执行listGET_OWNER_OF_NEXT_ENTRY前,注意此时pxIndex指向Task1TCB->xStateListItem,所以( pxConstList )->pxIndex->pxNext;Task2TCB->xStateListItem,所以这次pvOwner取到的是Task2TCB赋值给pxCurrentTCB.

对于优先级2,当第三次执行listGET_OWNER_OF_NEXT_ENTRY前,注意此时pxIndex指向Task2TCB->xStateListItem,这时符合上面的if条件了,所以( pxConstList )->pxIndex->pxNext;Task1TCB->xStateListItem,所以这次pvOwner取到的是Task1TCB赋值给pxCurrentTCB.

这样就实现了同一优先级下的任务时间片轮流执行。

taskRESET_READY_PRIORITY()
#define taskRESET_READY_PRIORITY( uxPriority )\
 {\
 if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) )\
    == ( UBaseType_t ) 0 )\
 {\
 portRESET_READY_PRIORITY( ( uxPriority ),\
 ( uxTopReadyPriority ) );\
 }\
 }

taskRESET_READY_PRIORITY()函数的妙处在于清除优先级位图表uxTopReadyPriority中相应的位时候,会先判断当前优先级链表下是否还有其它任务,如果有则不清零。 假设任务1会调用 vTaskDelay(),会将自己挂起,只能是将任务1从就绪列表删除,不能将任务1在优先级位图表uxTopReadyPriority中对应的位清0,因为该优先级下还有任务2,否则任务2将得不到执行.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章