zoukankan      html  css  js  c++  java
  • 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执行该任务。

    温润如玉,坚毅如铁。
  • 相关阅读:
    如何在一个项目中同时包含mvc建站、webapi接口
    解决api、WebService跨域问题
    mvc接口、webapi、webservice 对比
    云服务器 远程mysql 无法连接
    c#快速写本地日志
    使用筛选器特性标记方法解决webapi 跨域问题
    流量控制(滑动窗口协议)
    解释Windows7“上帝模式”的原理
    Linux网络协议栈(二)——套接字缓存(socket buffer)
    理解MySQL——架构与概念
  • 原文地址:https://www.cnblogs.com/heisen/p/10579159.html
Copyright © 2011-2022 走看看