uC/OS-II任务调度之就绪表及最高优先级任务判定算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronnie_Hu/article/details/78633731

uC/OS-II是Jean J. Labrosse设计的完整的、可移植、可固化、可裁剪的抢占式实时多任务内核,绝大部分代码都是用标准的C语言编写的,开源、规模不大,比较适合初次接触嵌入式操作系统的人员学习和使用。2000年7月,uC/OS-II在一个航空项目中得到了美国联邦航空管理局(FAA)对用于商用飞机的、符合RTCA DO-178B标准的认证。


(一)在就绪表(Reday List)中作标记

每个任务的就绪标记都会被放入就绪表中,与就绪表相关的变量有两个,即OSRdyGrp和OSRdyTbl[]。

OSRdyGrp定位的是任务所在的行,OSRdyTbl[]定位的是任务所在的列。

OSRdyGrp的每一位都分别对应一个行(行号从0到7),OSRdyTbl[i]的每一位分别对应第i行的一个列(列号从0到7)。


1、OSRdyGrp

就绪任务所在的组,其定义位于UCOS_II.H,是一个8位无符号整型。OSRdyGrp哪个位为1就说明哪一行有就就绪的任务,源代码中的定义如下:

OS_EXT  INT8U        OSRdyGrp;                        /* Ready list group                              */

2、OSRdyTbl[]

就绪表,其定义位于UCOS_II.H,是一个一维数组。源代码中的定义如下:

#define  OS_RDY_TBL_SIZE   ((OS_LOWEST_PRIO) / 8 + 1)   /* Size of ready table                         */
OS_EXT  INT8U        OSRdyTbl[OS_RDY_TBL_SIZE];       /* Table of tasks which are ready to run         */

上面代码中的OS_LOWEST_PRIO的宏定义位于OS_CFG.H,对于uC/OS_II,该值最大为63。源代码中的定义如下:

#define OS_LOWEST_PRIO           60    /* Defines the lowest priority that can be assigned ...         */
                                       /* ... MUST NEVER be higher than 63!                            */

3、OSMapTbl[]

映射表,其定义位于OS_CORE.C,是一个一维数组,包含8个元素。源代码中的定义如下:

/*
*********************************************************************************************************
*                              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};


以下代码用于将任务放入就绪表,prio为任务的优先级。

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

举例:假如只有一个任务,该任务的优先级prio = 11 = 00 001 011,高三位为001,低三位为011,则

OSRdyGrp = OSMapTbl[prio >> 3] = OSMapTbl[1] = 0x02 = 0000 0010

OSRdyTbl[prio >> 3] = OSRdyTbl[1] = OSMapTbl[3] = 0x08 = 0000 1000

这样,向任务就绪表的第1行第3列写1,即完成了该任务的就绪标记写入。


(二)找出进入就绪状态的优先级最高的任务

4、OSUnMapTbl[]

优先级判定表,其定义位于OS_CORE.C,是一个一维数组,包含256个元素。源代码中的定义如下:

/*
*********************************************************************************************************
*                                       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
};

算法如下:

y    = OSUnMapTbl[OSRdyGrp]; 
x    = OSUnMapTbl[OSRdyTbl[y]]; 
prio = (y << 3) + x; 


举例:假设有3个任务,优先级分别为10、21、53

对于优先级为10的任务:

prio = 00 001 010

OSRdyGrp = OSMapTbl[prio >> 3] = OSMapTbl[1] = 0x02 = 0000 0010

OSRdyTbl[prio >> 3] = OSRdyTbl[1] = OSMapTbl[2] = 0x04 = 0000 0100

对于优先级为21的任务:

prio = 00 010 101

OSRdyGrp = OSMapTbl[prio >> 3] = OSMapTbl[2] = 0x04 = 0000 0100

OSRdyTbl[prio >> 3] = OSRdyTbl[2] = OSMapTbl[5] = 0x04 = 0010 0000

对于优先级为53的任务:

prio = 00 110 101

OSRdyGrp = OSMapTbl[prio >> 3] = OSMapTbl[6] = 0x40 = 0100 0000

OSRdyTbl[prio >> 3] = OSRdyTbl[6] = OSMapTbl[5] = 0x04 = 0010 0000

最后OSRdyGrp的值就是将所有的OSMapTbl[prio>>3]进行按位或运算:

OSRdyGrp = 0000 0010 | 0000 0100 | 0100 0000 = 0100 0110 = 70

同理,OSRdyTbl[1] = 0000 0100,OSRdyTbl[2] = 0010 0000,OSRdyTbl[6] = 0010 0000


然后,根据优先级判定表OSUnMapTbl[],可以确定优先级最高的任务

OSRdyGrp = 70

y = OSUnMapTbl[OSRdyGrp] = OSUnMapTbl[70] = 1

x = OSUnMapTbl[OSRdyTbl[y]] = OSUnMapTbl[OSRdyTbl[1]] = OSUnMapTbl[4] = 2

prio = (y << 3) + x = 10,即处于就绪状态的优先级最高的任务是优先级为10的任务。


这样做的好处其实就是以空间来换取时间,提高程序执行的效率。如果我们自己设计,首先想到的算法可能就是定义一个一维数组OSRdy[],包含64个元素,对应64个任务,当某个任务处于就绪状态时,就将相应的元素置1,比如优先级53的任务就绪,那么就令OSRdy[53] = 1,这样一来,通过查找法可以找到位于就绪状态的优先级最高的任务,其弊端就是当处于就绪状态的优先级最高的任务比较靠后时(比如优先级为63),查找所消耗的时间较多,效率相对较低,而uC/OS-II中采用的算法只用几行代码就可以快速找到优先级最高的任务,且对不同的任务所消耗的时间基本一致、相对公平。


猜你喜欢

转载自blog.csdn.net/Ronnie_Hu/article/details/78633731
今日推荐