uc/os调度机制深度解析

一、准备工作:

//OSMapTbl与OSUnMapTbl定义
/*
*********************************************************************************************************
*                              MAPPING TABLE TO MAP BIT POSITION TO BIT MASK
*
* Note: Index into table is desired bit position, 0..7
*       Indexed value corresponds to bit mask
*********************************************************************************************************
*/

INT8U  const  OSMapTbl[]   = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

/*
*********************************************************************************************************
*                                       PRIORITY RESOLUTION TABLE
*
* Note: Index into table is bit pattern to resolve highest priority
*       Indexed value corresponds to highest priority bit position (i.e. 0..7)
*********************************************************************************************************
*/

INT8U  const  OSUnMapTbl[] = {
    0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

需要理解的变量:OSMapTbl[](INT8U)、OSUnMapTbl[](INT8U)、OSRdyGrp(INT8U)、OSRdyTbl[](INT8U)
需理解的关系:OS_EVENT::OSEventGrp <---->OSRdyGrp, OS_EVENT::OSEventTbl <----> OSRdyTbl。

二、先来理解变量:

OSMapTbl是优先级映射表,设计者将它设计为与数组下标对应的位置为1,其他位0,例如OSMapTbl[0] = 0x01是因为下标为0,因此将0位置1即0x01.(具体设计者是怎样想到的就不是我这种沙雕能触及的了)。
OSUnMapTbl:优先级解映射表,设计者将0x00--0xff这256个数值中最低位为1的位号都列了出来,例如OSUnMapTbl[1] = 0的原因是0x01最低为为1的位号是0。(同上,不要问本雕为什么)
OSRdyGrp:全局组优先级
OSRdyTbl:全局组内优先级
ps:后两个变量有点抽象,需要结合起来理解。按我的理解,设计者将每个任务的优先级(0~63)分为了两段,首先将该优先级转化为二进制,然后从左到右依次编号0~7,使用2~4位来表示组优先级,使用5~7位来表示组内优先级,至于0~1位设计者是没有使用的(不要问本雕为什么)。那么问题来了,怎样使用这两个全局变量来存取多个不同优先级的任务呢?

我们假设某个任务的优先级表示记为prio
让我先来介绍两个表达式:

OSRdyGrp |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio&0x07];

这或许很显而易见了:设计者用“或”运算将不同优先级先分组,然后再在组内记录该任务的优先级。让我们来看一个例子:假设初始时OSRdyGrp = 0,OSRdyTbl所有元素都为0,prio = 5.那么prio二进制表示为0b0000 0101,那么OSRdyGrp |= OSMapTbl[prio >> 3]的结果为0x01;OSRdyTbl[prio >> 3] |= OSMapTbl[prio&0x07]结果为0x20.这样就把优先级分段表示了。到这里,我想大家会有两个问题:你怎么取出刚刚存储进去的优先级呢?(或者说怎么验证存储进去的优先级就是5呢?)刚刚只存储了一个任务,怎么存储多个不同优先级的任务呢?哈哈,我们一个一个解决。
先看第一个问题,我们现在有两个已知条件:OSRdyGrp = 0x01,OSRdyTbl[0] = 0x20.首先我们取出组优先级存于变量y中:y = OSUnMapTbl[OSRydGrp],即y = 0;然后我们取出组内优先级存于变量x中:x = OSUnMapTbl[OSRdyTbl[y]] = OSUnMapTbl[0x20] = 5;于是我们再用一个通用表达式:curprio = (y << 3) + x;即curprio = 5.这样就求出了之前存进去的优先级。

先停一下,我们来总结一下目前为止我们知道了些什么:
首先,拿到一个任务的优先级prio,我们通过 OSRdyGrp |= OSMapTbl[prio >> 3];OSRdyTbl[prio >> 3] |= OSMapTbl[prio&0x07];这两个表达式将优先级存到OSRdyGrp和OSRdyTbl中。
其次,我们使用逆过程y = OSUnMapTbl[OSRydGrp];x = OSUnMapTbl[OSRdyTbl[y]];curprio = (y << 3) + x,来求得当前所存储的优先级中的最高优先级。注意,取出的是最高优先级,不是随便一个。

那么我们继续第二个问题:假设我有两个任务,优先级分别是1和6,初始时OSRdyGrp = 0,OSRdyTbl所有元素都为0.我首先将他们都存到OSRdyGrp和OSRdyTbl中:
1的二进制表示为0b0000 0001;
6的二进制表示为0b0000 0110;
先存优先级1(先存储哪个优先级都不重要):OSRdyGrp |= OSMapTbl[1 >> 3],OSRdyGrp = 0x01;
OSRdyTbl[1 >> 3] |= OSMapTbl[1 & 0x07],OSRdyTbl[0] = 0x02;
再存优先级6:OSRdyGrp |= OSMapTbl[6 >> 3],OSRdyGrp = 0x01 | 0x01 = 0x01;
OSRdyTbl[6 >> 3] |= OSMapTbl[6 & 0x07],OSRdyTbl[0] = 0x02 | 0x40 = 0x41;

Ok,存储完成,此时OSRdyGrp = 0x01,OSRdyTbl[0] = 0x42。那么我们开始取(记住,我们要取的是当前最大优先级,也就是1):
y = OSUnMapTbl[OSRdyGrp] = OSUnMapTbl[1] = 0;
x = OSUnMapTbl[OSRdyTbl[y]] = OSUnMapTbl[0x42] = 1;
因此,curprio = (y << 3) + x = 1;
那么既然把此优先级取出来了,就应该把他从存储库中删除。设计者很机智,在每次取出一个优先级的过程中,他记录了组优先级所在的位,以及组内优先级所在的位:组优先级位bity = OSMapTbl[y],组内优先级位bitx = OSMapTbl[x];
就刚刚取出的1优先级来说,bity = 0x01,bitx = 0x02;那么取出1优先级后,我们用 OSRdyTbl[y] &= ~bitx,即OSRdyTbl[y] = 0x40;若此时OSRdyTbl[y] == 0x00,说明y优先组中没有任务了,那么就用OSRdyGrp &= ~bity;删除该组。

显然,提取了优先级1后,我们有OSRdyGrp = 0x01,OSRdyTbl[0] = 0x40.于是我们再提取:
y = OSUnMapTbl[OSRdyGrp] = OSUnMapTbl[1] = 0;
x = OSUnMapTbl[OSRdyTbl[y]] = OSUnMapTbl[0x40] = 6;
curprio = (y << 3) + x = 6;
提取后,刚好OSRdyTbl[0] = 0x00,OSRdyGrp = 0x00.over

好了,优先级调度的基本思想就是这样。但是这还不能用于ucos中直接使用,因为它现在只是独立的东西,需要与其他东西联动才能完成重任。

三、我们来看看关系:

那么我们就结合V操作来看看吧:
复习一下V操作,就是执行一个等待任务,然后再让信号量资源加一。
对应到ucos中,V操作就是函数 INT8U OSSemPost(OS_EVENT* pevent),该函数中调用了函数OS_EventTaskRdy(OS_ENVET* pevent,void* msg,INT8U msk),OS_EventTaskRdy函数中有这么一段:

y = OSUnMapTbl[pevent->OSEventGrp];
bity = OSMapTbl[y];
x = OSUnMapTbl[pevent->OSEventTbl[y]];
bitx = OSMapTbl[x];
prio = (INT8U)((y << 3) + x);
if ((pevent->OSEventTbl[y] &= ~bitx) == 0x00) {
pevent->OSEventGrp &= ~bity;
} 

对,就是这么熟悉。但是又有一丝不同,主要就是,OSRdyGrp换成了 OS_EVENT::OSEventGrp,OSRdyTbl换成了OS_EVENT::OSEventTbl。因此可以猜测,这两对是有“激情”的。这就要追溯到P操作中了,P操作中有一个调用了一个函数:OS_EventTaskwait(OS_EVENT* pevent),它是这样写的:

void OS_EventTaskWait (OS_EVENT *pevent)
{
OSTCBCur->OSTCBEventPtr = pevent; /* Store pointer to event control block in TCB */
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) { /* Task no longer ready */
OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Clear event grp bit if this was only task pending */
}
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
}

简要介绍一下里边了每个变量:
OSTCBCur(OS_TCB*):全局变量,当前事件控制块
OS_TCB::OSTCBBitX(INT8U):组内优先级访问掩码,作用类似于bitx;
OS_TCB::OSTCBBitY(INT8U):组优先级访问掩码,作用类似于bity;

那么OS_EVENT::OSEventGrp <---->OSRdyGrp, OS_EVENT::OSEventTbl <----> OSRdyTbl这两对好基友的关系也就确认了,确实可以等价。那么理解OS_EventTaskRdy(OS_ENVET* pevent,void* msg,INT8U msk)就不难了,他其实就是将被阻塞的任务由阻塞态转为就绪态,将状态记录到OSRdyGrp和OSRdyTbl中。
然后在V操作中还调用了一个函数OS_Sched(),该函数就是直接从OSRdyGrp和OSRdyTbl中直接获取当前最大优先级任务,然后调用OS_TASK_SW执行该任务。

原文地址:https://www.cnblogs.com/heisen/p/10579159.html

时间: 2024-07-31 12:03:05

uc/os调度机制深度解析的相关文章

Goroutine并发调度模型深度解析之手撸一个协程池

golanggoroutine协程池Groutine Pool高并发 并发(并行),一直以来都是一个编程语言里的核心主题之一,也是被开发者关注最多的话题:Go语言作为一个出道以来就自带 『高并发』光环的富二代编程语言,它的并发(并行)编程肯定是值得开发者去探究的,而Go语言中的并发(并行)编程是经由goroutine实现的,goroutine是golang最重要的特性之一,具有使用成本低.消耗资源低.能效高等特点,官方宣称原生goroutine并发成千上万不成问题,于是它也成为Gopher们经常

spark快速入门与WordCount程序机制深度解析 spark研习第二季

2.spark wordCount程序深度剖析 标签: spark 一.Eclipse(scala IDE)开发local和cluster (一). 配置开发环境 要在本地安装好java和scala. 由于spark1.6需要scala 2.10.X版本的.推荐 2.10.4,java版本最好是1.8.所以提前我们要需要安装好java和scala并在环境变量中配置好. 下载scala IDE for eclipse安装 连接:http://scala-ide.org/download/sdk.h

类加载机制深度解析

一.类加载过程 多个java文件经过编译打包生成可运行jar包,最终由java命令运行某个主类的main启动程序,这里需要先通过类加载器把主类加载到JVM 主类在运行过程中如果使用到其他类,会逐步加载这些类. 注意:jar包里的类不是一次性全部加载的,是使用到时才加载,不过类似于java.lang.Object这种支持JVM运行的类会在启动时便被加载. 类加载过程 加载>>验证>>准备>>解析>>初始化>>使用>>卸载 加载:在硬盘上

Android图片编码机制深度解析(Bitmap,Skia,libJpeg)

问题 工作中遇到了Android中有关图片压缩保存的问题,发现这个问题还挺深,而且网上资料比较有限,因此自己深入研究了一下,算是把这个问题自顶至下全部搞懂了,在此记录. 相关的几个问题如下: 1.Android系统是如何编码压缩保存图片的? 2.Skia库起到的作用? 3.libJpeg库起到的作用? 4.能不能自己调用Skia或libJpeg? 解答 一谈到Android上的图片压缩保存,基本都会想到android.graphics.Bitmap这个类,它提供了一个非常方便(事实上也只有这一个

java 序列化机制深度解析

概要 序列化机制允许将实现序列化的Java对象转换为字节序列,这些字节序列可以被保存在磁盘上或通过网络传输,以备以后重新恢复原来的对象,序列化机制使得对象可以脱离程序的运行而独立存在 可序列化的类包括:实现了Serializable的类,数组,枚举,String类也是可序列化对象 由于序列化保存的是对象的状态,因此不会保存类的静态变量 -通过ObjectOutputStream和ObjectInputStream对对象进行序列化及反序列化 虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一

源码深度解析SpringMvc请求运行机制

本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请求给springMvc开始,到返回数据给客户端期间是怎么运转的. 1.用户请求处理过程: 1.用户发送请求时会先从DispathcherServler的doService方法开始,在该方法中会将ApplicationContext.localeResolver.themeResolver等对象添加到request中,紧接着就是调用doDisp

源码深度解析SpringMvc请求运行机制(转)

源码深度解析SpringMvc请求运行机制 本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请求给springMvc开始,到返回数据给客户端期间是怎么运转的. 1.用户请求处理过程: 1.用户发送请求时会先从DispathcherServler的doService方法开始,在该方法中会将ApplicationContext.localeResolver.themeResolver等对象添加到

uC/OS 的任务调度解析 (转)

uC/OS 的任务调度解析 1.任务调度器启动之后(初始化,主要是TCB的初始化),就可以创建任务,开始任务调度了,实际上第一个任务准确的说不是进行任务切换,而是进行启动当前最高优先级任务.uC/OS使用的是OSStartHighRdy OSStartHighRdy LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority LDR R1, =NVIC_PENDSV_PRI STRB R1, [R0] MOVS R0, #0 ; Set

Flink 源码解析 —— 深度解析 Flink 序列化机制

Flink 序列化机制 https://t.zsxq.com/JaQfeMf 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac 上搭建 Flink 1.6.0 环境并构建运行简单程序入门 3.Flink 从0到1学习 -- Flink 配置文件详解 4.Flink 从0到1学习 -- Data Source 介绍 5.Flink 从0到1学习 -- 如何自定义 Data Source ? 6.Flink 从0到1学习 -- Da