μC-OSⅡ操作系统任务调度

如何描述一个task

代码描述
μC-OSⅡ操作系统任务调度
把内部的固定执⾏函数来看,task就是⼀个执⾏的函数,⼀个⽆限循环的void函数

• 为什么是⽆限循环? 因为⼀个任务要在系统当中不断地调度,⽽不是⽤⼀次就废了
• 为什么返回void,task是独⽴存在的,不需要为其他task做什么(即便需要也是共享或者通信)

下⾯我们通过代码进程块来了解⼀下task进程块在计算机当中的使⽤(调度)⽅法。
μC-OSⅡ操作系统任务调度
μC-OSⅡ操作系统任务调度
上⾯两段代码分别是两个task的代码。在循环外的代码主要⽬的是设置时钟节拍(晶体振荡器),剩下⼏个是寻找对应的引脚来控制指定引脚灯的开关(初始化)

A控制开灯,B控制关灯。

在µcOS操作系统当中维护着⼏个队列

  1. 就绪队列:等待执⾏的task,等待现在正在执⾏的task退出然后即可进⼊
  2. 延迟队列:延时的时间节拍不为0,暂时不能执⾏

为了防⽌CPU空转,在任务管理器当中设置⼀个空任务IDLE,简单讲就是占着茅坑不拉屎,等着别 ⼈去占⽤他。

有了这些基础知识,我们来看这两个任务如何⼯作的

• 什么时候这些task被创建?操作系统当中有两种模式:核模式和运⾏模式(这个词我给搞忘了) 只有在核模式下才可以创建任务。⼀般情况下,时间中断(也同样是个task,完成调度的任务) 会打断运⾏进⼊核模式,创建任务
• 在哪被创建?在µcOS当中,为了保证时间复杂度的确定性,我们没有虚拟内存,都在内存当中 被创建,放⼊就绪队列当中。
• 如何启动任务执⾏? 时间中断的task会在就绪队列当中选择优先级最⾼的task出队执⾏

在第⼀个时间⽚当中,A从就绪队列当中出队,执⾏,OSTimeDLy让他进⼊延迟队列当中,然后 IDLE任务进⼊。

第⼀个时间⽚结束,时间中断任务进⼊,把所有延迟队列当中内容OSTimeDLy减1,选择就绪队列 当中第⼆个任务执⾏。

⼆到九时间⽚都是IDLE空转,直到第10个时间⽚的时候,A的OSTimeDLy变为0,移⼊就绪队列当 中再次执⾏。

所以灯是10个时间⽚⼀闪,再亮10个时间⽚的循环

task 和 process的区别是什么

μC-OSⅡ操作系统任务调度
μC-OSⅡ操作系统任务调度
我们还是通过上⾯的例⼦来说,上⾯两个例⼦两次的输出都是什么?

1 还是 2?

答案是task是1 process是2

task某种程度上可以理解为线程,他不像进程⼀样会产⽣阻塞。

task的控制核⼼->TCB描述任务

前⾯我们提到的task都是⼀个⼤的概念,这⾥我们通过细节的分析这个数据结构来掌握任务的管控情况。

除去额外的成员,TCB的组织基本如下(后⾯是占⽤字节数⽬的⼤⼩)

OS_STK *OSTCBStkPtr 4(堆栈指针)

Os_tcb * OSTCBNext 4(双向链表的下⼀个)

Os_tcb * OSTCBPrev 4 (上⼀个)

Unsigned short OSTCBDly 2 (时延)

Unsigned char OSTCBStat 1 (状态)

Unsigned char OSTCBPrio 1 (优先级)

Unsigned char OSTCBX 1 Unsigned char OSTCBY 1

Unsigned char OSTCBBitX 1 Unsigned char OSTCBBitY 1

后⾯四个我们逐⼀来介绍

OSTCBNext 和 OSTCBPrev

这两个成员揭示了任务的存储⽅式即双向链表

为了⽅便,我们在boot初始化的时候就创建所有的TCB,64个(分别对应64个优先级)前两个是
系统的优先级(⽤于处理紧急事件,⽐如掉电),后两个就是IDLE和系统监测(⽐如CPU温度)

所有的TCB都通过⼀个双向链表相连,称为TCBFreeList。

显⽽易⻅,双向链表虽然能⾃适应的调整空间,但是查询时很慢的,所有系统当中还维护⼀个优先 级队列(实质上是⼀个数组) 数组下标和优先级⼀⼀对应。

OSTCBStat

如果⼀个系统想要运⾏起来,就必须有⼀个完整的没有死状态的状态循环表,µcOS如下
μC-OSⅡ操作系统任务调度
这⾥可以看到我们之前提到的timetick(延迟队列到ready队列)

OSTCBX OSTCBY OSTCBBitX OSTCBBitY
μC-OSⅡ操作系统任务调度
为了加速对最⾼优先级的查询过程,系统当中设计了⼀个数据结构标定任务是否被占⽤

这个⽅阵当中,如果被占⽤则为1,未占⽤则为0,(这⾥不是⼆维数组,⽽是⼀个数的不同 位!!!)

PriorityReadyTable有8个数字,每个表示这⼀⾏当中的8个优先级是否有被占⽤

PriorityReadyGroup只有1个,8位,如果PriorityReadyTable的任意⼀项全部为0,则置0,否则为 1.即检测该⾏是否有优先级被占⽤。

OSTCBX和OSTCBY分别对应着prio的⾼三位和低三位,也就分别对应着这个类似⼆维数组的两个索引。我们可以通过X和Y进⾏访问当前节点

OSTCBBitX OSTCBBitY的内容出现的⽬的是为了快速访问,也就是变成掩码的形式
μC-OSⅡ操作系统任务调度
通过这两个掩码可以快速的访问⾃⼰的占⽤状态,并改变。

所以建⽴这个表有什么⽤?通过优先级位图法来快速查找最⾼优先级是多少

优先级位图法最重要的思想就是空间换时间。构造⼀个查找表如下
μC-OSⅡ操作系统任务调度
priorty table对应的是不同的值的,256个分别代表着8位数的不同情况,来找到最⼤的1的位置。

当我们要寻找最⾼优先级的时候

  1. 以priortyGroup为下标访问priortyDecisionTable的内容,迅速得到最⾼优先级所在的table⾏ (⾼三位)
  2. 以prirotytable[i]为下标访问priortyDecisionTable的内容得到最⾼优先级所在的位置(低三位)

通过得到的优先级索引,迅速访问优先级队列,调⽤对应的TCB进⾏执⾏