ucos的任务调度

在今天的文章中,我将重点回顾ucos的任务调度机制,解迷ucos任务调度细节。为了更好的理解任务调度的机制,我们需要提前复习几个关键的知识点,做好知识的基础工作。

ucos任务变迁图

在ucos的世界中,任务具备五种状态:就绪态,运行态,中断态,睡眠态和等待态。一个任务在其生命周期内,根据开发人员的代码逻辑设计会不断在这五种状态中进行着迁移。

任务管理结构TCB都有啥

TCB翻译过来就是任务管理块的意思,即有关任务的全部信息细节,都可以通过这样一个数据结构来表示。具体而言,TCB代码表示的数据结构如下图所示:

对里面重要的结构变量,进行一下解析:

  • 第一部分的OSTCBStkPtr,指向当前任务堆栈的栈顶。具体任务的堆栈,其功能详见下文的描述。UcosII允许用户自定义每个任务的堆栈大小,这样可以使用户根据每个任务实际的需要合理分配堆栈大小,便于节省RAM的空间(因为堆栈都是占用RAM空间的)。
  • 第二部分的5个参数,我们可以看到,是受到宏OS_TASK_CREATE_EXT_EN的控制。这个宏定义在OS_CFG.H中,用于控制是否使用创建任务的扩展功能。
  1. OSTCBExtPtr:指向用户定义的扩展内容的指针。
  2. OSTCBStkBottom:任务栈的栈底指针。
  3. OSTCBStkSize:可以容纳指针单位的数目,注意不是BYTE为单位。
  4. OSTCBOpt:主要在使用创建任务扩展功能中使用,将选项值传递给创建任务接口。
  5. OSTCBId:任务识别码,暂未使用。
  • 第三部分的两个指针,为TCB双向链表的前后向指针。该链表主要应用于系统时钟节拍函数。
  1. OSTCBNext:TCB双向链表的后向指针
  2. OSTCBPrev:TCB双向链表的前向指针

  • 第四部分的7个参数,主要用于存储任务的各种信息:
  1. OSTCBDly:任务对应的挂起等待时间单位长度。
  2. OSTCBStat:任务的状态存储变量,对应任务的5个装填。
  3. OSTCBPrio:任务的优先级。
  4. OSTCBX,OSTCBY,OSTCBBitX,OSTCBBitY:与任务的优先级存在对应关系,用于加速调度过程中优先级的比较。

堆和栈

堆栈,这两个字经常会被放在一起使用。但是我们必须知道,堆是堆(Heap),栈是栈(Stack)。两者虽然都是存储空间的一种,但是存在一定的差别。不能等同使用。

  • 栈:由操作系统自动分配释放,存放函数的参数值,局部变量的值等。
  • 堆:一般由程序员分配释放。类似C语言中的malloc和free,操作的空间就是堆空间。

这里很多细节可以自行百度一下,不再熬述。为了后面理解方便,我们可以简单记忆任务中定义的局部变量都是存放于栈中。而调用malloc和free操作的空间都是存放在堆空间。两者都是存放在RAM中

ucos任务调度

ucos中的任务切换都是由ucos的调度器来完成的,那么任务是怎样调度的?调度现场是如何保存和回复的?这将是本章节要讨论的。首先,我们来复习一下,ucos中的多个任务是如何进行调度和切换的?在ucos中,任务级别的调度由OS_SCHED()完成,而中断级别的调度由OS_INTEXT()完成

那么什么是任务级别的调度呢?简单的说,就是可以在任务中主动触发的ucos系统的任务调度。同理,中断级别的调度,就是可以在中断退出的时候触发的ucos系统的任务调度。肯定有人要问了,为啥要触发任务调度呢?系统不是自己调度的么

说的没错,ucos系统是自己负责调度任务。而我们的触发动作也都被ucos封装到了特定的API接口中,在我们调用这些API的时候(这些调用的地方,我们可以称为调度点),就会触发OS_SCHED()的调用。举个例子说明一下:

定个前提:假定任务A的优先级高于任务B。在任务A的逻辑代码实现中,为了保证其他低优先级的任务能够抢占到CPU资源,调用OSTimeDly函数主动让出CPU控制权。这里让出控制权的过程中,就会触发ucos进行实时任务的调度过程(可以简单理解为启动任务B,挂起任务A)。具体OSTimeDly接口的代码如下所示,我们一起来分析一下;

第一个红框所示:OSTimeDly先将当前运行的任务(任务A)移出就绪队列,放到事件队列中。第二个红框,是这个接口的重点,即挂起任务A后,OSTimeDly主动调用OS_SCHED()接口!!!!从而触发了ucos的任务调度机制!

ucos任务调度点

ucos操作系统在应该进行调度的调度点,都为我们封装好了对应的API。通过调用这些API,其实就是间接的调用了OS_SCHED接口,触发ucos系统的任务调度和切换过程。在ucos系统中,共计有10处调度点

ucos任务切换

任务调度的过程中,CPU会将待运行的任务信息导入CPU硬件资源中。这就涉及到了“现场”的概念。现场,和经常看到的破案影视作品的现场真的是一个意思。

通俗的讲,任务在CPU运行的时候,会将对应的TCB中的一些信息,任务运行的信息,代码段的信息,记录到CPU对应的硬件寄存器中。CPU根据硬件寄存器中的信息,在指定的流水线周期内,进行二进制指令码的运行动作。比如我们常见的CPU的PC指针,这个指针指向的是下一行要执行的代码段代码的具体位置。

当任务切换发生时,对于CPU寄存器而言,存在两个相反的动作:CPU寄存器保存和CPU寄存器恢复

  • CPU寄存器保存:也可以称作现场保存。当任务切换发生的时候,需要将此时的CPU寄存器信息存入当前任务的TCB块中(由OSTcbCur获取当前任务TCB控制块)具体如下图所示:

  • CPU寄存器恢复:也可以称作现场恢复。任务切换发生时,在完成CPU寄存器信息存入当前任务TCB动作后,将调度器选定的即将占用CPU资源的任务TCB控制块中,对应CPU寄存器的值写入到CPU硬件寄存器中,实现CPU寄存器值的恢复,也即上一次任务切换现场的恢复。具体如下图所示:

ucos任务相关API

  1. 创建任务:OSTaskCreate ();
  2. 创建任务(扩展信息):OSTaskCreateExt ();
  3. 获取任务信息:OSTaskQuery ();
  4. 任务挂起:OSTaskSuspend ();
  5. 任务恢复:OSTaskResume ();
  6. 任务删除:OSTaskDelReq ();
  7. 请求删除任务:OSTaskDelReq ();
  8. 任务优先级调整:OSTaskChangePrio ();
  9. 堆栈检验:OSTaskStkChk ();

以上内容,仅仅是个人的经验总结,如有疏漏和错误地方,还请各位知友批评指正共同进步。另外如果想对嵌入式操作系统有深入和权威的了解,还可以自行阅读以下书籍。本文章系列仅仅站在答主个人的理解角度,力求用通俗的语言向嵌入式爱好者们普及嵌入式的一些理论和实战知识。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值