手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(二)
继续……
if (ticks > 0u) { /* 延时参数是否为0 */OS_ENTER_CRITICAL(); /* 禁止中断 */y = OSTCBCur->OSTCBY;OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;if (OSRdyTbl[y] == 0u) {OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;}OSTCBCur->OSTCBDly = ticks;OS_EXIT_CRITICAL(); /* 开启中断 */OS_Sched();}
在上一段代码中,出现了一个陌生的数组: OSRdyTbl[],跟踪这个变量可以找到它的定义,发现它仅仅是一个uint8型的数组,长度是8个。
可以明确的告诉大家,这个数组很重要,应该算是任务优先级调度核心参数之一,与下面那个参数OSRdyGrp 合起来便可以作为任务就绪表。
※接下来需要讲UCOSII系统的任务优先级调度策略,这一段有些复杂,需要反复思考,查阅大量的资料。
UCOSII的优先级策略
UCOSII操作系统最大可以管理64个任务(255个的暂时不讨论),每个任务都有唯一的优先级,从0开始到64,数字越小优先级越高,越优先进行系统调用,为了方面管理和调度,系统把64任务的优先级进行了分组。
每8个优先级为一组,一共8组。
举例:
以前我上幼儿园的时候,我们小班有64个小朋友,每个小朋友都有自己的学号(从0到63),老师为了方面管理,把我们分成了8个小组(从0到7),每组8个小朋友……作为小朋友的我来说,当然不理解这样分组的意义,不过对于老师而言,这样做肯定是有用的。
下面是分组以后小朋友的坐席表:
当有一个名叫波波的小朋友的学号是12的时候,那他属于哪个组?看下图,当然是第1组,而且我的座位号排第5(8,9,10,11,12)
当一个任务的优先级确定了以后,那么它的组号和在组内的坐席号都是确定的,是永远不可能发生改变的,所以在任务创建之时,这些信息都可以完全决定下来,现在再回想那两句代码,意义是不是瞬间就明白了?
当一个任务被创建以后,他所属的组号必然就等于优先级的二级制的高3位,比如……下图:
根据上面那个图,那么这两句代码的意义也就很清楚了:
ptcb->OSTCBY = (INT8U)(prio >> 3u);ptcb->OSTCBX = (INT8U)(prio & 0x07u);
就是根据任务的优先级,计算出组号和组内编号。
至于这两个数据有什么用,分组出来有什么意义?请在小朋友波波的带领下继续往下看。
刚才那个陌生的数组: OSRdyTbl[8]之所以被称为任务就绪表,是因为它里面保存的是当前所有任务的就绪状态,它的长度是8,每一个元素代表一个组,比如 OSRdyTbl[0]代表第0组, OSRdyTbl[1]代表第1组,OSRdyTbl[2]代表第2组……以此类推。
由于它的数据类型是数据uint8,所以每一个元素中的每一个位(bit)代表组内的任务的就绪状态(1为就绪,0为未就绪)。
举例:
比如,当优先级为12 的任务就绪时,那么对应的OSRdyTbl[1]的第4位bit,绝对等于1……当整个系统中,当只有优先级为12的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[1] 绝对等于0x10。
再比如,当优先级为0 的任务就绪时,那么对应的OSRdyTbl[0]的第0位bit,绝对等于1……当整个系统中,当只有优先级为0的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[0] 绝对等于0x01。
再再比如,当优先级为63 的任务就绪时,那么对应的OSRdyTbl[7]的第8位bit,绝对等于1……当整个系统中,当只有优先级为63的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[7] 绝对等于0x80。
再再再比如,当优先级为0和1的任务就绪时,那么对应的OSRdyTbl[0]的第0位bit以及第1位bit,都绝对等于1……当整个系统中,当只有优先级为0和1的任务就绪,其他所有任务都没有就绪时,那么OSRdyTbl[0] 绝对等于0x03。
小朋友们,现在理解了吗?上面的话要认真理解,理解完后才可以继续往下看。
当一个任务进入延时函数后,这个任务首先要暂停/休眠(把自己的就绪状态取消),再要把CPU的执行权交给别的任务(把别的任务设置为就绪),这个过程也就是任务的切换。
然后现在我们可以继续读代码了:
if (ticks > 0u) { /* 0 means no delay! */OS_ENTER_CRITICAL();y = OSTCBCur->OSTCBY; /* Delay current task */OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;if (OSRdyTbl[y] == 0u) {OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;}OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */OS_EXIT_CRITICAL();OS_Sched(); /* Find next task to run! */}
红色的那句代码所表达的意思,就是把当前任务的就绪表从1设置为0,从而使自身进入休眠状态。
当优先级为12的任务进入此地,那么OSTCBCur->OSTCBY和y必然等于1,OSTCBCur->OSTCBBitX必然等于0x10(他的座位号是第4),OSRdyTbl[1]在执行红色代码之前,肯定是等于0x10(假如当前只有12这一个就绪任务)。
经过这样一个取反在相与的计算,直接就把OSRdyTbl[1]的第4位bit的清空了,也就是把就绪状态,设置成了未就绪状态。
if (ticks > 0u) { /* 0 means no delay! */OS_ENTER_CRITICAL();y = OSTCBCur->OSTCBY; /* Delay current task */OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;if (OSRdyTbl[y] == 0u) {OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;}OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */OS_EXIT_CRITICAL();OS_Sched(); /* Find next task to run! */}
这一句代码,表示什么意思呢?
OSRdyTbl[]数组中的每个元素都代表了8个优先级任务的状态,按照字面意思解读,如果OSRdyTbl[x] == 0x00 (二进制00000000),那么就表示,当前这个组里面,没有任何就绪的任务。
跟踪变量OSRdyGrp ,可以找到它就是一个uint8型的数据,那么OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;这代码本身的意思无需多言,也就是清空这个数据的某个bit。
OSRdyGrp 这个变量的作用是管理任务就绪组的组号,原理和OSRdyTbl[]数组差不多,这个拥有8个bit的变量,每一个bit代表一个组,只要这个组内有任何一个任务就绪,那么这个变量对应的bit位,就会置为1,只有该组内所有的任务都是未就绪的状态,对应的那个bit才会被清零,逻辑算法上是或的关系。
举例:
比如,系统中只有任务0就绪了,那么OSRdyGrp 便等于 0x01(二进制00000001)。
比如,系统中只有任务12就绪了,那么OSRdyGrp 便等于 0x02(二进制00000010)。
比如,系统中只有任务63就绪了,那么OSRdyGrp 便等于 0x80(二进制10000000)。
比如,系统中有任务0和任务1都就绪了,那么OSRdyGrp 便等于 0x01(二进制00000001)。
比如,系统中有任务0和任务63都就绪了,那么OSRdyGrp 便等于 0x81(二进制10000001)。
回到代码,因为同一个组内的所有任务都是逻辑或的关系,所以在同一个组内的所有任务都没有就绪的情况下,才能把这个变量的对应bit位清空,只要有一个任务就绪,哪怕其余7个任务都没有就绪,也不能清空,这个if实现的就是这个功能。
总结一下这四个变量的意义:
ptcb->OSTCBY :当前任务优先级所属于的分组(0~7),比如优先级为12的任务,这个变量应该就是1
ptcb->OSTCBX :当前任务优先级在组内的序号,比如优先级为12的任务,这个变量应该就是4
ptcb->OSTCBBitY :用于逻辑运算的二进制变量,当前任务优先级所属于的组号,在变量OSRdyGrp 中的所占的bit的偏移,比如优先级为12的任务,组号排在第一个位置,那么这个变量应该就是二进制00000010
ptcb->OSTCBBitX :用于逻辑运算的二进制变量,当前任务优先级在组内的序号所占的bit偏移,比如优先级为12的任务,排在第五个位置,因此这个变量应该就是二进制00010000
现在理解这些变量的意义了吗?
if (ticks > 0u) { /* 0 means no delay! */OS_ENTER_CRITICAL();y = OSTCBCur->OSTCBY; /* Delay current task */OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;if (OSRdyTbl[y] == 0u) {OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;}OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */OS_EXIT_CRITICAL();OS_Sched(); /* Find next task to run! */}
上面那一句代码的意思是,记录当前任务需要的延时时间(后面讲具体的实现机制),比如当我调用delay_ms(5000),那样记录的就是5000,但我调用delay_ms(100)记录的就是100,只不过单位可能不同,我这里写的毫秒,是因为我在系统的配置文件中把系统的节拍设置成了毫秒:
#define OS_TICKS_PER_SEC 1000u /* Set the number of ticks in one second */
这个宏定义系统的滴答定时器,每一秒钟发生多少个节拍,我定义的是1000,所以每个节拍就是1ms,因此延时函数也是这个级别(其实这样不太好,因为节拍太密集,系统的负荷会很重,实际肯定会根据需要调整成稍微大一些的数)。
以上,进入延时函数的任务切换中,把当前任务的就绪状态设置为未就绪的流程就讲解完毕了,接下来讲解如何唤醒一个新的任务。
待续……
转载于:https://www.cnblogs.com/han-bing/p/8883426.html
手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(二)相关推荐
- 手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(五)
继续...... 整个UCOSII嵌入式操作系统的任务调度策略便是如此,现在进行一个总结: 某个任务在执行中,每隔一定周期发生滴答时钟中断,在中断中遍历整个任务链表,更新每个任务的延时时间,修改就绪状 ...
- 手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(一)
刚参加工作那几年做MCU程序,由于实现的功能和需求都比较简单,外围模块也很少,所以大多数的项目直接就在裸机上写代码.当时也没有任务和线程的概念,脑子里想的只有单个函数的调度,变量的控制等等.工作时先把 ...
- 手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(三)
继续...... if (ticks > 0u) { /* 0 means no delay! */OS_ENTER_CRITICAL();y = OSTCBCur->OSTCBY; /* ...
- 手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(四)
继续...... 再回到那个重要得函数: void OS_Sched (void) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU ...
- 【ROS入门-4】嘴对嘴讲解ROS的核心概念——ROS话题通信机制
文章目录 前言 ROS系列文章 ROS的通信机制 话题(topic) 发布者 订阅者 消息(Message) 用C++来写话题通信的代码 发布者 订阅者 使用rqt_graph 源码附录 引用说明 参 ...
- 【ROS入门-3】嘴对嘴讲解ROS的核心概念——节点与节点管理器
文章目录 前言 ROS系列文章 ROS的通信机制 节点(Node) 节点管理器(Master) 简单运行 引用说明 参考 前言 我要给大家来介绍一下ROS当中一些核心的概念,帮助大家去在后面的ROS学 ...
- 手把手,嘴对嘴教你Spring Cloud 微服务实战 -- 前言
Spring Cloud 总结 博主接触到Spring Cloud 大概已经一年多了,当时Spring Cloud微服务框架已经是潮流了,不会一点都不好意思出去面试.并且主流技术基本上都在谈论微服务, ...
- 深入研究嵌入式操作系统的绝佳教材
前 言 本书作者多年的嵌入式领域研发.管理和教学经验,促成了本书的诞生. 本书的目的 操作系统是一个古老的话题,它的出现和发展,对于计算机技术来说,意义非凡.这种发展不仅仅体现在传统的计算机中,在强调 ...
- 三种嵌入式操作系统的分析与比析
1.1 嵌入式系统 嵌入式系统是以嵌入式计算机为技术核心,面向用户.面向产品.面向应用,软硬件可裁减的,适用于对功能.可靠性.成本.体积.功耗等综合性能有严格要求的专用计算机系统. 嵌入式系统应具有的 ...
最新文章
- [Spark][翻译]Spark 架构: Shuffle过程分析
- PMCAFF 微课堂 | 赶集、暴风影音这些优质App为什么都在做积分商城?
- 直播预告丨爆款独立站如何利用数据提升经营效率?
- php 获取URL 各部分参数
- 知名的php cms,20款最为知名的开源PHP CMS
- 操作系统:第四章 文件管理2 - 磁盘管理,磁盘调度算法
- 开发人员需要了解的有关xPaaS的一切
- matlab动画_弹簧振子振动的matlab动画演示
- 安卓 App 库存系统开发 终端设备 SDK 分析
- Visio的下载和安装
- android高德地图获取省市编码,android中高德地图地理编码
- 网页音乐视频不让下载怎么办
- m4s格式转换mp3_简单的amr转换mp3音频格式转换方法
- 如何在国外做好自然科学研究-2
- 行满秩矩阵为何变成增广矩阵还为满秩
- 2012年寒假假期总结
- echarts设置坐标轴标题的样式
- 桥 Gym100712H Bridges
- 4-2毕达哥拉斯三元组
- matlab柱状图之间连续,matlab 离散曲线图、连续曲线图、柱状图
热门文章
- anaconda tensorflow 2.3_TensorFlow 速成 | 统计师的Python日记 第13天
- linux 进程装入 物理内存 页表,linux进程空间一步步探究.doc
- 刚从阿里、头条面试回来,尚硅谷java数据结构与算法百度云
- 机器学习(MACHINE LEARNING)MATLAB中微分方程的求解
- android 单例模式详解,android开发设计模式之——单例模式详解
- erwin连接oracle数据库,erwin连接oracle9i数据库
- 哈利波特 pdf_干货!哈利波特英文原版pdf免费领,(含音频)词汇量大于新概念!...
- oauth2中用户的信息如何动态获取和存储_oAuth2.0 简介
- linux 退出服务器_Vue实战091:Vue项目部署到nginx服务器
- 制作精美的网站首页模板应该如何操作?