uCOSIII任务调度原理及使用方法

  1. 任务调度的概念

任务调度就是中止当前正在运行的任务转而去执行其他的任务。在uCOSIII中任务的调度通过两个函数实现:

任务级调度器函数:OSSched()

中断级调度器函数:OSIntExit()

  1. 任务调度的时机

情况

备注

当前任务给其他任务发信号,结束时调用

任务调用提交服务函数OS_Post(),发送信号量或消息给其它任务时调度发生

任务调用OSTimeDlyHMSM()或OSTimeDly()

如果延时参数不是0,调度发生。调度会在该任务被放入挂起队列后马上执行。

任务所等待的事件发生或超时

任务取消挂起

新任务被创建

任务被删除

内核对象被删除

任务所等待的内核对象被删除时(事件标志组、信号量、消息队列、mutex都是内核对象),这些任务就可能被就绪。然后调度发生。

任务改变自身优先级或其它任务优先级

任务调用OSTaskSuspend()停止自身

任务调用OSTaskResume()恢复其它停止了的任务

当退出中断服务程序

调度器调用OSIntExit()函数开始调度而不是OSSched()

用OSSchedLock()锁调度器

需要注意的是,锁调度器可以被嵌套,解锁次数必须等于加锁次数

用OSSchedRoundRobinYield()任务放弃了分配给它的时间片

用户程序调用OSSched()

OSSched()应用在任务中,OSIntExit()应用在中断函数中,由于uCOSIII为可剥夺式内核,所以在进入中断后退出时因为OSIntExit()的缘故可能导致退出后进入另外高于原优先级的人进程中。

  1. 过程分析

当发生任务调度时通过OSSched()及OSIntExit()函数实现任务的调度。

3.1 OSSched()

OSSched()函数定义在“os_core.c”文件中,其代码如下所示:

其调度发生的主要流程:寻找当前优先级最高的就绪任务等级,再在就绪任务表中执行对应优先级的就绪任务。

在程序中通过OS_PrioGetHighest()函数得到当前最高优先级就绪任务的优先等级,给到变量OSPrioHighRdy,再在就绪任务表OSRdyList[]中通过OSPrioHighRdy执行对应优先级的就绪任务(OSTCBHighRdyPtr指针指向得到的最高优先级的就绪任务)。需要注意的是,每一个就绪任务的优先级只有一个,但是每一个优先级下可能由于用户的任务配置存在多个同优先级的就绪任务,此时需要采用时间片轮转调度的方式轮流执行该优先级下的就绪任务。

得到最高优先级就绪任务后,判断当前任务(OSTCBCurPtr)是否为最高优先级,若不是则需要任务切换,否则继续执行。

3.2OSIntExit()

OSIntExit ()函数定义在“os_core.c”文件中,其代码如下所示:

与OSSched()处理流程类似,也是寻找当前优先级最高的就绪任务等级,再在就绪任务表中执行对应优先级的就绪任务。不在赘述,有所区别的是OSSched()发生在任务进程中,OSIntExit()发生在中断中。

  1. 最高优先级任务寻找

如前文所述在uCOSIII中寻找最高优先级的就绪任务需要通过两个步骤首先OS_PrioGetHighest()函数得到最高优先级就绪任务的等级,再通过任务就绪表OSRdyList[]找到最高优先级就绪任务,在这个过程中调用了OS_PrioGetHighest()函数及OSPrioTbl[]和OSRdyList[]两个变量。

4.1 优先级映射表OSPrioTbl[]

OSPrioTbl[]定义在“os_prio.c”中其本质为一个数组,数组的大小由宏定义OS_PRIO_TBL_SIZE确定,该宏定义的数值通过配置的最大优先级数量和单片机INT型变量位大小计算得到。

因此,优先级位映射表的容量大小与用户设置的最大任务优先级数量及应用的单片机INT型数据位大小有关。该表如下图所示,表元素的位宽度根据CPU_DATA大小确定。

通过上图可以发现映射表的元素高低位设置为低位在左高位在右,这是由于单片机有一条特殊的指令“计算前导零(CLZ)”,利用该指令配合优先级位映射表可以快速找到最高优先级就绪任务。

当对应优先级的任务就绪时,通过OS_PrioInsert()函数使优先级位映射表对应的优先级位置1。当对应优先级的任务均结束时,通过OS_PrioRemove()使对应的优先级位清零。

4.2 就绪任务表OSRdyList[]

OSRdyList[]定义在“os.h”中,其本质为OS_RDY_LIST结构体的数组。

表的大小与用户设定的最大优先级数量OS_CFG_PRIO_MAX有关。表中每一个元素结构形式为OS_RDY_LIST的结构体:

包含头指针,尾指针,及当前就绪任务数量。因此每一个优先级下可能存在多个同一优先级的就绪任务,故在优先级映射表中需要判断当前优先级任务是否完全结束才可以清零。头指针指向第一个优先级就绪任务,尾指针指向最后一个优先级就绪任务(此时每个就绪任务根据就绪状态发生时间的先后进行排序,也就是该任务添加的先后顺序)。

4.3 OS_PrioGetHighest()

OS_PrioGetHighest()定义在“os_prio.c”中,代码如下图所示。

其主要功能是在wile()循环中按组寻找置位的优先级组别,再通过“计算前导零”功能指令快速得到最高优先级的任务等级。

  1. 总结

uCOSIII中的任务调度通过OSSched()及OSIntExit()实现。其基本流程位:通过OS_PrioGetHighest()函数利用优先级映射表OSPrioTbl[]寻找最高优先级就绪任务的优先级,再在就绪任务表OSRdyList[]中执行就绪的任务。

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值