uCOS-II 基础入门教程(七)

 

任务调度(Task Scheduling)

μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那一个。确定哪个任务优先级最高,下面该哪个任务运行了的工作是由调度器(Scheduler)完成的。任务级的调度是由函数OSSched()完成的中断级的调度是由另一个函数OSIntExt()完成的,这个函数将在以后描述。OSSched()的代码如程序:

void OSSched (void)

{

    INT8U y;

 

 

    OS_ENTER_CRITICAL();

    if ((OSLockNesting | OSIntNesting) == 0) {                          (1)

        y             = OSUnMapTbl[OSRdyGrp];                              (2)

        OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);   (2)

        if (OSPrioHighRdy != OSPrioCur) {                                (3)

            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];                  (4)

            OSCtxSwCtr++;                                                      (5)

            OS_TASK_SW();                                                      (6)

        }

    }

    OS_EXIT_CRITICAL();

}

μC/OS-Ⅱ任务调度所花的时间是常数,与应用程序中建立的任务数无关。如程序(1)条件语句的条件不满足,任务调度函数OSSched()将退出,不做任务调度。这个条件是:如果在中断服务子程序中调用OSSched(),此时中断嵌套层数OSIntNesting>0,或者由于用户至少调用了一次给任务调度上锁函数OSSchedLock(),使OSLockNesting>0。如果不是在中断服务子程序调用OSSched(),并且任务调度是允许的,即没有上锁,则任务调度函数将找出那个进入就绪态且优先级最高的任务(2),进入就绪态的任务在就绪任务表中有相应的位置位。一旦找到那个优先级最高的任务,OSSched()检验这个优先级最高的任务是不是当前正在运行的任务,以此来避免不必要的任务调度(3)。注意,在μC/OS中曾经是先得到OSTCBHighRdy然后和OSTCBCur做比较。因为这个比较是两个指针型变量的比较,在8位和一些16位微处理器中这种比较相对较慢。而在μC/OS-Ⅱ中是两个整数的比较。并且,除非用户实际需要做任务切换,在查任务控制块优先级表OSTCBPrioTbl[]时,不需要用指针变量来查OSTCBHighRdy。综合这两项改进,即用整数比较代替指针的比较和当需要任务切换时再查表,使得μC/OS-Ⅱ比μC/OS在8位和一些16位微处理器上要更快一些。

为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是通过将以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的(4)。接着,统计计数器OSCtxSwCtr加1,以跟踪任务切换次数(5)。最后宏调用OS_TASK_SW()来完成实际上的任务切换(6)。

任务切换很简单,由以下两步完成,将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先级的任务的寄存器值从栈中恢复到寄存器中。在μC/OS-Ⅱ中,就绪任务的栈结构总是看起来跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,μC/OS-Ⅱ运行就绪态的任务所要做的一切,只是恢复所有的CPU寄存器并运行中断返回指令。为了做任务切换,运行OS_TASK_SW(),人为模仿了一次中断。多数微处理器有软中断指令或者陷阱指令TRAP来实现上述操作。中断服务子程序或陷阱处理(Trap hardler),也称作事故处理(exception handler),必须提供中断向量给汇编语言函数OSCtxSw()。OSCtxSw()除了需要OS_TCBHighRdy指向即将被挂起的任务,还需要让当前任务控制块OSTCBCur指向即将被挂起的任务。

    OSSched()的所有代码都属临界段代码。在寻找进入就绪态的优先级最高的任务过程中,为防止中断服务子程序把一个或几个任务的就绪位置位,中断是被关掉的。为缩短切换时间,OSSched()全部代码都可以用汇编语言写。为增加可读性,可移植性和将汇编语言代码最少化,OSSched()是用C写的。

 

给调度器上锁和开锁(Locking and UnLocking the Scheduler)

 

    给调度器上锁函数OSSchedlock()(程序清单L3.9)用于禁止任务调度,直到任务完成后调用给调度器开锁函数OSSchedUnlock()为止,(程序清单L3.10)。调用OSSchedlock()的任务保持对CPU的控制权,尽管有个优先级更高的任务进入了就绪态。然而,此时中断是可以被识别的,中断服务也能得到(假设中断是开着的)。OSSchedlock()和OSSchedUnlock()必须成对使用。变量OSLockNesting跟踪OSSchedLock()函数被调用的次数,以允许嵌套的函数包含临界段代码,这段代码其它任务不得干预。μC/OS-Ⅱ允许嵌套深度达255层。当OSLockNesting等于零时,调度重新得到允许。函数OSSchedLock()和OSSchedUnlock()的使用要非常谨慎,因为它们影响μC/OS-Ⅱ对任务的正常管理。

    当OSLockNesting减到零的时候,OSSchedUnlock()调用OSSched[L3.10(2)]。OSSchedUnlock()是被某任务调用的,在调度器上锁的期间,可能有什么事件发生了并使一个更高优先级的任务进入就绪态。

    调用OSSchedLock()以后,用户的应用程序不得使用任何能将现行任务挂起的系统调用。也就是说,用户程序不得调用OSMboxPend()、OSQPend()、OSSemPend()、OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()或OSTimeDlyHMSM(),直到OSLockNesting回零为止。因为调度器上了锁,用户就锁住了系统,任何其它任务都不能运行。

    当低优先级的任务要发消息给多任务的邮箱、消息队列、信号量时,用户不希望高优先级的任务在邮箱、队列和信号量没有得到消息之前就取得了CPU的控制权,此时,用户可以使用禁止调度器函数。

void OSSchedLock (void)

{

    if (OSRunning == TRUE) {

        OS_ENTER_CRITICAL();

        OSLockNesting++;

        OS_EXIT_CRITICAL();

    }

}

 

void OSSchedUnlock (void)

{

    if (OSRunning == TRUE) {

        OS_ENTER_CRITICAL();

        if (OSLockNesting > 0) {

            OSLockNesting--;

            if ((OSLockNesting | OSIntNesting) == 0) {                    (1)

                OS_EXIT_CRITICAL();

                OSSched();                                                      (2)

            } else {

                OS_EXIT_CRITICAL();

            }

        } else {

            OS_EXIT_CRITICAL();

        }

    }

}

 

 

空闲任务(Idle Task)

μC/OS-Ⅱ总是建立一个空闲任务,这个任务在没有其它任务进入就绪态时投入运行。这个空闲任务[OSTaskIdle()]永远设为最低优先级,即OS_LOWEST_PRI0。空闲任务OSTaskIdle()什么也不做,只是在不停地给一个32位的名叫OSIdleCtr的计数器加1,统计任务使用这个计数器以确定现行应用软件实际消耗的CPU时间。

 

void OSTaskIdle (void *pdata)

{

    pdata = pdata;

    for (;;) {

        OS_ENTER_CRITICAL();

        OSIdleCtr++;

        OS_EXIT_CRITICAL();

    }

}

UCOS_II基础入门:

uCOS-II 基础入门教程(一)

uCOS-II 基础入门教程(二)

uCOS-II 基础入门教程(三)

uCOS-II 基础入门教程(四)

uCOS-II 基础入门教程(五)

uCOS-II 基础入门教程(六)

扫一扫关注微信公众号,获取更多实时的嵌入式资讯,嵌入式学习指导方法,汽车电子最新资讯等。。

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值