uC/OS-III之任务调度总结

1.任务调度
任务调度,简单的理解就是确定下一个要执行的任务。uC/OS-III中的任务调度通过任务调度器实现。uC/OS-III是一个可剥夺型的、基于优先级的内核。

2.调度点
任务调度,说白了其实就是在某些时刻进行任务的调度,这些调度的时刻称为调度点。
在uC/OS-III中的任务调度点有以下几种:
(1)任务释放信号量或给另一个任务或向另一个任务发消息
(2)任务调用延时函数OSTimeDly()或OSTimeDlyHMSM()
(3)任务等待事件发生而事件还未发生
(4)任务取消等待
(5)创建任务
(6)删除任务
(7)删除一个内核对象
(8)任务改变自身的优先级或者其他任务的优先级
(9)任务通过调用OSTaskSuspend()将自身挂起
(10)任务“解除挂起”某一调用OSTaskSuspend()挂起的任务
(11)退出所有的嵌套中断
(12)通过OSSchedUnlock()给调度器解锁
(13)任务调用OSSchedRoundRobinYield()放弃其执行时间片
(14)用户调用OSSched()

3.时间片轮转调度
这里需要说明一下的是,在uC/OS-III中加入了时间片轮转调度。这里只是解释一下它,具体的调度细节需要参考《嵌入式实时操作系统》P101。
当两个或更多的任务拥有相同的优先级时,uC/OS-III允许一个任务运行一段指定的时间(又叫时间片),然后轮转到下一个任务,这个过程叫做时间片轮转调度。

4.调度实现细节
任务调度通过两个函数实现:OSSched()和OSIntExit()。其中OSSched()是任务级的调度器,而在中断服务程序中必须调用OSIntExit()。
(1)OSSched()函数的源码位于文件os_core.c文件,358行 - 387行

void  OSSched (void)
{
    CPU_SR_ALLOC();                                      // 宏定义,声明变量cpu_sr,用来临时存放CPU的状态寄存器的值

    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {           // 确认不是在中断服务程序中被调用的
        return;
    }
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {     // 确认调度器没有上锁
        return;
    }

    CPU_INT_DIS();                                       // 禁止中断
    OSPrioHighRdy   = OS_PrioGetHighest();               // 在就绪优先级位映射表中查找就绪态的优先级最高的任务的优先级
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;  // 用查找的优先级作为索引,获取最高优先级任务的任务控制块OS_TCB
    if (OSTCBHighRdyPtr == OSTCBCurPtr) {                // 确保最高优先级的任务不是当前任务
        CPU_INT_EN();                                    // 使能中断
        return;
    }

#if OS_CFG_TASK_PROFILE_EN > 0u
    OSTCBHighRdyPtr->CtxSwCtr++;                         // Inc. # of context switches to this task
#endif
    OSTaskCtxSwCtr++;                                    // Increment context switch counter

    OS_TASK_SW();                                        // 执行任务级的任务切换
    CPU_INT_EN();                                        // 使能中断
}

(2)OSIntExit()函数的代码位于os_core.c文件中,275行 - 315行

void  OSIntExit (void)
{
    CPU_SR_ALLOC();                                      // 宏定义,声明变量cpu_sr,用来临时保存CPU的状态寄存器的值

    if (OSRunning != OS_STATE_OS_RUNNING) {              // 确保OS已启动
        return;
    }

    CPU_INT_DIS();                                       // 禁止中断
    if (OSIntNestingCtr == (OS_NESTING_CTR)0) {          // 确保OSIntNestingCtr不会向下溢出
        CPU_INT_EN();                                    // 使能中断
        return;
    }
    OSIntNestingCtr--;
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {           // 确保已退出所有的中断嵌套
        CPU_INT_EN();                                    // 使能中断
        return;
    }
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {     // 确保调度器未上锁
        CPU_INT_EN();                                    // 使能中断
        return;
    }

    OSPrioHighRdy   = OS_PrioGetHighest();               // 在就绪优先级位映射表中查找就绪态的优先级最高的任务的优先级
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;  // 用查找的优先级作为索引,获取最高优先级任务的任务控制块OS_TCB
    if (OSTCBHighRdyPtr == OSTCBCurPtr) {                // 确保最高优先级的任务不是当前任务
        CPU_INT_EN();                                    // 使能中断
        return;
    }

#if OS_CFG_TASK_PROFILE_EN > 0u
    OSTCBHighRdyPtr->CtxSwCtr++;                         // Inc. # of context switches for this new task
#endif
    OSTaskCtxSwCtr++;                                    // Keep track of the total number of ctx switches

    OSIntCtxSw();                                        // 执行中断级的任务切换
    CPU_INT_EN();                                        // 使能中断
}

(3)OS_SchedRoundRobin()函数位于文件os_core.c中,2491行 - 2544行
该函数用来执行时间片轮转调度的。当选择“直接发布(derect post)”模式时,OS_SchedRoundRobin()由OSTimeTick()调用;当选择“延迟发送(deferred post)”模式时,OS_SchedRoundRobin()由OS_IntQTask()调用。

void  OS_SchedRoundRobin (OS_RDY_LIST  *p_rdy_list)
{
    OS_TCB   *p_tcb;
    CPU_SR_ALLOC();                           // 宏定义,定义变量cpu_sr,用来临时保存CPU的状态寄存器的值

    if (OSSchedRoundRobinEn != DEF_TRUE) {    // 确保时间片轮转调度允许
        return;
    }

    CPU_CRITICAL_ENTER();                     // 进入临界区
    p_tcb = p_rdy_list->HeadPtr;              // 获取当前任务的任务控制块OS_TCB
    if (p_tcb == (OS_TCB *)0) {               // 确保任务不为空
        CPU_CRITICAL_EXIT();                  // 退出临界区
        return;
    }
    if (p_tcb == &OSIdleTaskTCB) {            // 确保当前任务不是空闲任务
        CPU_CRITICAL_EXIT();                  // 退出临界区
        return;
    }

    if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {  // 递减时间片计数器
        p_tcb->TimeQuantaCtr--;
    }
    if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {  // 查看任务的时间片是否使用完
        CPU_CRITICAL_EXIT();                  // 退出临界区
        return;
    }

    if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {      // 查看当前任务优先级下的就绪任务列表表项的任务数是否大于2
    CPU_CRITICAL_EXIT();                               // 退出临界区
        return;
    }

    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {   // 查看任务调度器是否上锁
        CPU_CRITICAL_EXIT();                           // 退出临界区
        return;
    }

    OS_RdyListMoveHeadToTail(p_rdy_list);     // 把当前任务的任务控制块OS_TCB移动到该任务就绪表的尾部
    p_tcb = p_rdy_list->HeadPtr;              // 从任务就绪表的头部获取新任务的任务控制块OS_TCB
    if (p_tcb->TimeQuanta == (OS_TICK)0) {    // 查看新任务控制块OS_TCB的时间片的长度是否未设置
        p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;  // 时间片长度设置成按照默认值
    } else {
        p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;                // 载入新任务的时间长度
    }
    CPU_CRITICAL_EXIT();                      // 退出临界区
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值