空闲任务(Idle Task)和统计任务

μC/OS-Ⅱ总是建立一个空闲任务,这个任务在没有其它任务进入就绪态时投入运行。这个空闲任务[OSTaskIdle()]永远设为最低优先级,即OS_LOWEST_PRI0。空闲任务OSTaskIdle()什么也不做,只是在不停地给一个32位的名叫OSIdleCtr的计数器加1,统计任务(见3.08节,统计任务)使用这个计数器以确定现行应用软件实际消耗的CPU时间。程序清单L3.11是空闲任务的代码。在计数器加1前后,中断是先关掉再开启的,因为8位以及大多数16位微处理器的32位加1需要多条指令,要防止高优先级的任务或中断服务子程序从中打入。空闲任务不可能被应用软件删除。

 

程序清单 L3.11 μC/OS-Ⅱ的空闲任务.

void OSTaskIdle (void *pdata)

{

    pdata = pdata;

    for (;;) {

        OS_ENTER_CRITICAL();

        OSIdleCtr++;

        OS_EXIT_CRITICAL();

    }

}

μC/OS-Ⅱ有一个提供运行时间统计的任务。这个任务叫做OSTaskStat(),如果用户将系统定义常数OS_TASK_STAT_EN(见文件OS_CFG.H)设为1,这个任务就会建立。一旦得到了允许,OSTaskStat()每秒钟运行一次(见文件OS_CORE.C),计算当前的CPU利用率。换句话说,OSTaskStat()告诉用户应用程序使用了多少CPU时间,用百分比表示,这个值放在一个有符号8位整数OSCPUsage中,精读度是1个百分点。

如果用户应用程序打算使用统计任务,用户必须在初始化时建立一个唯一的任务,在这个任务中调用OSStatInit()(见文件OS_CORE.C)。换句话说,在调用系统启动函数OSStart()之前,用户初始代码必须先建立一个任务,在这个任务中调用系统统计初始化函数OSStatInit(),然后再建立应用程序中的其它任务。程序清单L3.12是统计任务的示意性代码。

 

程序清单 L3.12 初始化统计任务.

void main (void)

{

    OSInit();                 /* 初始化uC/OS-II (1)*/

    /* 安装uC/OS-II的任务切换向量 */

    /* 创建用户起始任务(为了方便讨论,这里以TaskStart()作为起始任务) (2)*/

    OSStart();                /* 开始多任务调度 (3)*/

}

 

 

 

void TaskStart (void *pdata)

{

    /* 安装并启动uC/OS-II的时钟节拍 (4)*/

    OSStatInit();             /* 初始化统计任务 (5)*/

    /* 创建用户应用程序任务 */

    for (;;) {

        /* 这里是TaskStart()的代码! */

    }

}

 

因为用户的应用程序必须先建立一个起始任务[TaskStart()],当主程序main()调用系统启动函数OSStcnt()的时候,μC/OS-Ⅱ只有3个要管理的任务:TaskStart()、OSTaskIdle()和OSTaskStat()。请注意,任务TaskStart()的名称是无所谓的,叫什么名字都可以。因为μC/OS-Ⅱ已经将空闲任务的优先级设为最低,即OS_LOWEST_PR10,统计任务

的优先级设为次低,OS_LOWEST_PR10-1。启动任务TaskStart()总是优先级最高的任务。

F3.4解释初始化统计任务时的流程。用户必须首先调用的是μC/OS-Ⅱ中的系统初始化函数OSInit(),该函数初始化μC/OS-Ⅱ[图F3.4(2)]。有的处理器(例如Motorola的MC68HC11),不需要“设置”中断向量,中断向量已经在ROM中有了。用户必须调用OSTaskCreat()或者OSTaskCreatExt()以建立TaskStart()[图F3.4(3)]。进入多任务的条件准备好了以后,调用系统启动函数OSStart()。这个函数将使TaskStart()开始执行,因为TaskStart()是优先级最高的任务[图F3.4(4)]]。

 

F3.4统计任务的初始化

 

TaskStart()负责初始化和启动时钟节拍[图F3.4(5)]。在这里启动时钟节拍是必要的,因为用户不会希望在多任务还没有开始时就接收到时钟节拍中断。接下去TaskStart()调用统计初始化函数OSStatInit()[图F3.4(6)]。统计初始化函数OSStatInit()决定在没有其它应用任务运行时,空闲计数器(OSIdleCtr)的计数有多快。奔腾II微处理器以333MHz运行时,加1操作可以使该计数器的值达到每秒15,000,000次。OSIdleCtr的值离32位计数器的溢出极限值4,294,967,296还差得远。微处理器越来越快,用户要注意这里可能会是将来的一个潜在问题。

系统统计初始化任务函数OSStatInit()调用延迟函数OSTimeDly()将自身延时2个时钟节拍以停止自身的运行[图F3.4(7)]。这是为了使OSStatInit()与时钟节拍同步。μC/OS-Ⅱ然后选下一个优先级最高的进入就绪态的任务运行,这恰好是统计任务OSTaskStat()。读者会在后面读到OSTaskStat()的代码,但粗看一下,OSTaskStat()所要做的第一件事就是查看统计任务就绪标志是否为“假”,如果是的话,也要延时两个时钟节拍[图F3.4(8)]。一定会是这样,因为标志OSStatRdy已被OSInit()函数初始化为“假”,所以实际上DSTaskStat也将自己推入休眠态(Sleep)两个时钟节拍[图F3.4(9)]。于是任务切换到空

闲任务,OSTaskIdle()开始运行,这是唯一一个就绪态任务了。CPU处在空闲任务OSTaskIdle中,直到TaskStart()的延迟两个时钟节拍完成[图3.4(10)]。两个时钟节拍之后,TaskStart()恢复运行[图F3.4(11)]。 在执行OSStartInit()时,空闲计数器OSIdleCtr被清零[图F3.4(12)]。然后,OSStatInit()将自身延时整整一秒[图F3.4(13)]。因为没有其它进入就绪态的任务,OSTaskIdle()又获得了CPU的控制权[图F3.4(14)]。一秒钟以后,TaskStart()继续运行,还是在OSStatInit()中,空闲计数器将1秒钟内计数的值存入空闲计数器最大值OSIdleCtrMax中[图F3.4(15)]。

OSStarInit()将统计任务就绪标志OSStatRdy设为“真”[图F3.4(16)],以此来允许两个时钟节拍以后OSTaskStat()开始计算CPU的利用率。

统计任务的初始化函数OSStatInit()的代码如程序清单 L3.13所示。

 

程序清单 L3.13 统计任务的初始化.

void OSStatInit (void)

{

    OSTimeDly(2);

    OS_ENTER_CRITICAL();

    OSIdleCtr    = 0L;

    OS_EXIT_CRITICAL();

    OSTimeDly(OS_TICKS_PER_SEC);

    OS_ENTER_CRITICAL();

    OSIdleCtrMax = OSIdleCtr;

    OSStatRdy    = TRUE;

    OS_EXIT_CRITICAL();

}

 

统计任务OSStat()的代码程序清单L3.14所示。在前面一段中,已经讨论了为什么要等待统计任务就绪标志OSStatRdy[L3.14(1)]。这个任务每秒执行一次,以确定所有应用程序中的任务消耗了多少CPU时间。当用户的应用程序代码加入以后,运行空闲任务的CPU时间就少了,OSIdleCtr就不会像原来什么任务都不运行时有那么多计数。要知道,OSIdleCtr的最大计数值是OSStatInit()在初始化时保存在计数器最大值OSIdleCtrMax中的。CPU利用率(表达式[3.1])是保存在变量OSCPUsage[L3.14(2)]中的:

 

[3.1]表达式  Need to typeset the equation.

 

一旦上述计算完成,OSTaskStat()调用任务统计外界接入函数OSTaskStatHook() [L3.14(3)],这是一个用户可定义的函数,这个函数能使统计任务得到扩展。这样,用户可以计算并显示所有任务总的执行时间,每个任务执行时间的百分比以及其它信息(参见1.09节例3)。

 

程序清单 L3.14 统计任务

void OSTaskStat (void *pdata)

{

    INT32U run;

    INT8S usage;

 

    pdata = pdata;

    while (OSStatRdy == FALSE) {                                  (1)

        OSTimeDly(2 * OS_TICKS_PER_SEC);

    }

    for (;;) {

        OS_ENTER_CRITICAL();

        OSIdleCtrRun = OSIdleCtr;

        run          = OSIdleCtr;

        OSIdleCtr    = 0L;

        OS_EXIT_CRITICAL();

        if (OSIdleCtrMax > 0L) {

            usage = (INT8S)(100L - 100L * run / OSIdleCtrMax);    (2)

            if (usage > 100) {

                OSCPUUsage = 100;

            } else if (usage < 0) {

                OSCPUUsage = 0;

            } else {

                OSCPUUsage = usage;

            }

        } else {

            OSCPUUsage = 0;

        }

        OSTaskStatHook();                                         (3)

        OSTimeDly(OS_TICKS_PER_SEC);

    }

}


你可能感兴趣的:(空闲任务(Idle Task)和统计任务)