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将得不到执行.

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值