1.任务优先级表用途

优先级表用于指示在对应的优先级下是否存在就绪的任务,操作系统内核总是在优先级表中的最高优先级中选择任务执行,就绪表是动态更新的。
举个例子让大家理解一下任务优先级表:驾校学车。驾校里有车,教练,学员,我们假设驾校教练只有一辆车,进入车内练习的人就是处在运行状态,在旁边排队等待的学员就处在就绪状态。由于报名费不一样,学员分为VIP等级和普通等级,教练让学员上车时优先考虑VIP等级学员。

教练为学员做了一张排队表:

教练首先判断是否有VIP等级学员,当有VIP等级学员时,等级表中的VIP等级数值为1,教练会在VIP学员中选择一个让其上车练习,只有当VIP等级学员都练完放弃练习了,等级表中的VIP等级数值为0。教练才会判断是否有普通等级学员,当有普通等级学员时,等级表中的普通等级数值为1,教练会在普通等级学员中选择一个让其上车练习。

根据描述我们得出优先级表有两个特点:
1、优先级表指示在对应的优先级下是否存在就绪的任务。
2、任务状态会动态更新,优先级表也会随之动态更新。

2.任务优先级表的实现

任务优先级表用于指示在对应的优先级下是否存在就绪的任务,优先级表每一个元素用于指示对应的优先级下是否有就绪的任务。
因此使用静态数组的方法实现一个任务优先级表,C语言实现如下:

任务优先级表和任务的关系框图如下:

任务优先级表的数组中下标最大的元素task_priority_table[15]代表最高优先级,task_priority_table[0]代表最低优先级,任务优先级表有以下三个操作:
1、优先级置1。
2、优先级清0。
3、查找最高优先级。

C语言实现优先级置1:

C语言实现优先级清0:

C语言实现查找最高优先级:

使用静态数组的方法可以实现一个就绪表,有没有更高效的方法呢?
答案时有的,使用BIT位表的方法可以实现一个优先级表,并且更加高效,C语言实现如下:

一个u16类型的数据包含16个bit位,每个bit位可以对应一个优先级,设最高bit位(第15位)为最高优先级,最低bit位(第0位)为最低优先级,任务优先级表和任务的关系框图如下:

C语言实现优先级置1:

C语言实现优先级置0:

刚刚提到了BIT位表的方法更加高效,这种方法的高效体现再查找最高优先级操作中,有一些CPU支持计算前导零数量指令CLZ,使用计算前导零数量指令CLZ可以加速查找最高优先级操作中,实现查找最高优先级:

由于查找最高任务优先级的操作在操作系统内核操作中非常频繁,因此使用BIT位表和计算前导零数量指令的组合可以提高运行效率

3.FreeRTOS任务优先级表分析

FreeRTOS源码中与任务优先级表相关的代码如下:

FreeRTOS中使用一个32位的uxTopReadyPriority作为任务优先级BIT位表。uxTopReadyPriority中每一个bit位对应一个优先级,最高bit位(第31位)为最高优先级,最低bit位(第0位)为最低优先级。每一个bit位为1时代表该任务优先级中有就绪任务,bit位为0时代表该任务优先级中无就绪任务。

uxTopReadyPriority任务优先级表有三个操作:优先级置1,优先级清0,查找最高优先级。

portRESET_READY_PRIORITY
portRECORD_READY_PRIORITY
portGET_HIGHEST_PRIORITY

其中查找最高优先级使用了_clz计算前导零数量指令。

优先级置1策略
当有任务加入就绪表时,将相应的bit位置1,不用考虑该优先级下的就绪任务总数量,因为加入一个任务后,该优先级下的就绪任务总数量必然大于等于1。
优先级置1的函数调用流程如下:

prvAddTaskToReadyList ->
taskRECORD_READY_PRIORITY ->
portRECORD_READY_PRIORITY

优先级清0策略
当有任务从就绪表移除时,需要先将该优先级下的就绪任务总数量减一,如果该优先级下的就绪任务总数量为0时,此时需要将该优先级清0。代码如下:

/*   就绪表中移除当前任务 */
if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{/* 优先级表对应位清0 */portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
else
{mtCOVERAGE_TEST_MARKER();
}

查找最高优先级
当需要进行任务切换时,需要查找最高优先级,函数调用流程如下:

taskSELECT_HIGHEST_PRIORITY_TASK ->portGET_HIGHEST_PRIORITY

FreeRTOS任务优先级表和就绪表的关系框图如下:

4.任务优先级表的更新

前文描述了任务优先级表的三种操作:优先级置1,优先级清0,查找最高优先级。那么这里就产生了以下问题:
哪些情况下会对任务优先级表进行操作?任务优先级表何时更新?
参考FreeRTOS源码,优先级表的操作更新点如下(清0操作会判断该优先级下的就绪任务总数量):

xTaskCreate
xTaskCreate的作用是创建一个任务,该系统函数的调用流程如下:

xTaskCreate ->
prvAddNewTaskToReadyList  ->
prvAddTaskToReadyList  ->
taskRECORD_READY_PRIORITY  ->portRECORD_READY_PRIORITY

就绪表变化:任务插入到就绪表对应优先级列表的尾部,对应的优先级位置1。

vTaskDelete
vTaskDelete的作用是删除一个任务,该系统函数的调用流程如下:

vTaskDelete ->
taskRESET_READY_PRIORITY ->
portRESET_READY_PRIORITY

就绪表变化:任务从就绪表对应优先级列表中移除,对应的优先级位清0。

vTaskSuspend
vTaskSuspend的作用是暂停一个任务,该系统函数的调用流程如下:

vTaskSuspend ->
taskRESET_READY_PRIORITY->
portRESET_READY_PRIORITY

就绪表变化:任务从对应优先级列表中移除,对应的优先级位清0。

vTaskResume
vTaskResume的作用是恢复一个任务,该系统函数的调用流程如下:

vTaskResume ->
prvAddTaskToReadyList ->
portRECORD_READY_PRIORITY

就绪表变化:任务插入到就绪表中对应优先级列表的尾部,对应的优先级位置1。

vTaskPrioritySet
vTaskPrioritySet的作用是改变一个任务优先级,该系统函数的调用流程如下:

vTaskPrioritySet ->
uxListRemove ->
prvAddTaskToReadyList ->
portRECORD_READY_PRIORITY

就绪表变化:任务从就绪表中的当前优先级列表中移除,并将任务插入到设定的优先级列表的尾部,对应的优先级位置1。

vTaskDelay
vTaskDelay的作用是将当前任务从就绪表中移动到等待表中,该系统函数的调用流程如下:

vTaskDelay ->
taskRESET_READY_PRIORITY ->
portRESET_READY_PRIORITY

就绪表变化:任务从就绪表中移除,并将任务插入到等待表中,对应的优先级位清0。

xQueueSemaphoreTake
xQueueSemaphoreTake的作用是当前任务等待一个信号,该系统函数的调用流程如下:

xQueueSemaphoreTake ->
vListInsert ->
prvAddCurrentTaskToDelayedList ->
portRESET_READY_PRIORITY

就绪表变化:将当前任务插入到挂起中,并当前任务从就绪表中移除,最后将当前任务插入等待表中,对应的优先级位清0。

xQueueGenericSend
xQueueSemaphoreTake的作用是发生一个信号,该系统函数的调用流程如下:

xQueueGenericSend ->
xTaskRemoveFromEventList->
uxListRemove ->
prvAddTaskToReadyList ->
portRECORD_READY_PRIORITY

就绪表变化:将移除挂起表中的第一个任务,并该任务插入到就绪表中中对应优先级列表的尾部,对应的优先级位置1。

5.源码

typedef unsigned long UBaseType_t;PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority         = tskIDLE_PRIORITY;  /* Remove the task from the ready list before adding it to the blocked listas the same list item is used for both lists. */if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ){/* The current task must be in a ready list, so there is no need tocheck, and the port reset macro can be called directly. */portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); /*lint !e931 pxCurrentTCB cannot change as it is the calling task.  pxCurrentTCB->uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */}else{mtCOVERAGE_TEST_MARKER();}#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 ) ) )

未完待续…
实时操作系统系列将持续更新
创作不易希望朋友们点赞,转发,评论,关注。
您的点赞,转发,评论,关注将是我持续更新的动力
作者:李巍
Github:liyinuoman2017

嵌入式实时操作系统7——任务优先级表相关推荐

  1. 嵌入式实时操作系统11——操作系统内核运行原理

    先展示一个操作系统运行动态图 1.操作系统内核关键知识点 本文将用一个实际的工程例子来剖析操作系统内核运行原理.在此之前我们先回顾一下之前文章讲述的重点知识点. <嵌入式实时操作系统3--任务切 ...

  2. 嵌入式实时操作系统ucos-ii_「正点原子NANO STM32开发板资料连载」第三十六章 UCOSII 实验 1任务调度...

    1)实验平台:alientek NANO STM32F411 V1开发板2)摘自<正点原子STM32F4 开发指南(HAL 库版>关注官方微信号公众号,获取更多资料:正点原子 第三十六章 ...

  3. 嵌入式实时操作系统ucos-ii_「正点原子NANO STM32开发板资料连载」第三十八章 UCOSII 实验 3...

    1)实验平台:alientek NANO STM32F411 V1开发板2)摘自<正点原子STM32F4 开发指南(HAL 库版>关注官方微信号公众号,获取更多资料:正点原子 第三十八章 ...

  4. 【012】SylixOS嵌入式实时操作系统助力中国航天事业

    SylixOS嵌入式实时操作系统助力中国航天事业 发布于2016年09月30日 2016年9月23日,翼辉信息与中国航天科技集团上海航天计算机技术研究所在上海完成SylixOS发行版风云翼辉嵌入式实时 ...

  5. 从零开始构建嵌入式实时操作系统2——重构

    1.前言 本人是一个普通的中年程序员,并不是圈内的大牛,写嵌入式操作系统这一系列的文章并不是要显示自己的技术,而是出于对嵌入式的热爱.非常幸运,本人毕业后的十几年一直从事嵌入式行业,遇到过各种坑,也收 ...

  6. RT-Thread 创始人熊谱翔:我和 Linux、嵌入式实时操作系统 RT-Thread

    我和 Linux.嵌入式实时操作系统 RT-Thread -- RT-Thread创始人熊谱翔,2015 年 接触 Linux 说起 Linux 应该从我在校园时期说起.我是在山城--重庆邮电学院念的 ...

  7. 嵌入式实时操作系统1——初识嵌入式实时操作系统

    嵌入式实时操作系统是什么 嵌入式实时操作系统是一个特殊的程序,是一个支持多任务的运行环境.嵌入式实时操作系统最大的特点就是"实时性",如果有一个任务需要执行,实时操作系统会立即执行 ...

  8. 嵌入式实时操作系统μC/OS II(一)

    嵌入式实时操作系统μC/OS II 为什么要学习μC/OS-II ㈠.凡从事嵌入式系统开发工作的人,必须对嵌入式操作系统有足够的了解. ㈡.对于初学者,从μC/OS-II开始是个明智的选择. 1.μC ...

  9. 基于STM32的简易示波器的UCOS II嵌入式实时操作系统实现

    基于STM32的简易示波器的UCOS II嵌入式实时操作系统实现 在基于STM32的示波器的实现的基础上,在STM32上移植UCOS II嵌入式实时操作系统. 在UCOS II操作系统中将各个功能分发 ...

最新文章

  1. Python实现俄罗斯方块
  2. PL/SQL常用方法汇总
  3. python用merge匹配和左连接_左手用R右手Python系列——数据合并与追加
  4. LeetCode Merge k Sorted Lists(有序单链表数组的合并)
  5. mel表达式_maya 2012 mel 表达式编辑器
  6. MyBatis中编写sql语句小于号报错
  7. python alpha beta_python – 使用alphabeta TicTacToe找到最佳移动
  8. 南洋股份拟57亿元收购天融信 老牌安全厂商曲线登录资本市场
  9. WordPress企业一号主题模板
  10. 图解 Go 切片的深拷贝和浅拷贝
  11. primefaces教程_PrimeFaces教程
  12. CreateProcess并隐藏窗口
  13. 正版卡巴斯基KIS7.0半年激活码免费领取
  14. 按键精灵---后台按键及鼠标操作
  15. matlab画运动轨迹,Matlab画小球沿轨迹运动
  16. 给IOS初学者及新手的建议
  17. 2021-02-05仅供自己参考:多态使用
  18. 多个pdf文件如何合并为一个文件?怎样将多个pdf文件合并到一个文件?
  19. roll() java_java.util.Calendar.roll(int field,int amount)方法实例
  20. 简练网软考知识点整理-项目风险审计及风险评估

热门文章

  1. 解决方案│POL全光校园解决方案 光纤到教室解决方案 光纤到宿舍解决方案
  2. 编程就是python吗_编程python是什么
  3. 密码对的还出现 Access denied for user ‘‘@‘localhost‘ (using password: NO) 错误
  4. 用python如何画出好看的地图
  5. 计算机视觉(CV)方向今年招聘情况怎么样?是否已经人才过剩?
  6. 从零开始搭建个人大数据集群——环境准备篇
  7. 百度云主机只能访问首页,bcloud_nginx_user.conf配置
  8. 服务器IUSR_机器名账号找不到怎么办?(转自百度问问)
  9. 2021.3.17丨致病菌毒力因子(VFDB)数据库注释
  10. 写不好 SQL? 送你一个大招