四. 就绪列表

准备运行的任务被放置于就绪列表中。就绪列表包括2 个部分:位映像组包含了优先级信息,一个表包含了所有指向就绪任务的指针。

一  优先级

显示了优先级的位映像组。它的宽度取决于CPU_DATA 的数据类型(见CPU.H),它可以是8 位、16 位、32 位。根据处理器相应地设定。
uC/OS-III 支持多达OS_CFG_PRIO_MAX 种不同的优先级(见OS_CFG.H)。在uC/OS-III 中,数值越小优先级越高。因此优先级0是优先级最高的。优先级OS_CFG_PRIO_MAX-1 的优先级最低。uC/OS-III 将最低优先级唯一地分配给空闲任务,其它任务不允许被设置为这个优先级。当任务准备好运行了,根据任务的优先级,位映像表中相应位就会被设置为1。如果处理器支持位清零指令CLZ,这个指令会加快位映像表的设置过程。


OS_PRIO.C 中包含了位映像表的设置、清除、查找的相关代码。这些函数都是uC/OS-III 的内部函数,可以用汇编语言优化。
函数 功能 
OS_PrioGetHighest() 查找最高优先级
OS_PrioInsert() 设置位映像表中相应的位
OS_PrioRemove() 清楚位映像表中相应的位

为了确定就绪列表中优先级最高的任务,位映像表会被扫描,通过OS_PrioGetHighest()函数找到优先级最高的任务。代码如下:

(1)OS_PrioGetHighest()函数扫描OSPrioTbl[]表直到找到非0的记录。这个循环最终会停止,因为总是有非0 记录(空闲任务的存在)。
(2) 当这个表中全是0 记录时,就会从下一个表中查找。优先级"prio"会被增加(如果表长32 位,就将prio 加上32)
(3)当找到第一个非0 位时,计算该位之前0 位的个数,返回该优先级值。如果CPU 提供清零指令,可以通过这个指令优化代码。如果CPU 没有这个指令,那么这个指令就只能用C 语言模拟了。函数CPU_CntLeadZeros()统计了CPU_DATA 记录中0 的个数(从左边开始,以位计)。例如,假定位映像表长32 位,0xF0001234 返回的非0 位前0 位数的个数是0。0x00F01234 返回的是8。

二  就绪列表

准备好运行的任务被放到就绪列表中,如图6-1。就绪列表是一个数组(OSRdyList[]),它一共有OS_CFG_PRIO_MAX 条记录,记录的数据类型为OS_RDY_LIST(见OS.H)。就绪列表中的每条记录都包含了三个变量.Entries 、.TailPtr 、.HeadPtr。

.Entries 中该优先级的就绪任务数。当该优先级中没有任务就绪时,.Entries 就会被设置为0。
.TailPtr 和.HeadPtr 用于该优先级就绪任务的建立双向列表。.HeadPtr 指向列表的头部,.TailPtr 指向列表的尾部。
表中的记录跟任务的优先级有关。例如,如果一个任务的优先级是5,那么当它就绪时会被放入OSRdyList[5]中。
表6-2 中列出了与就绪列表相关的操作函数。这些都是uC/OS-III的内部函数,用户不能调用它们。
函数名 功能
OS_RdyListInit() 初始化就绪列表为空
OS_RdyListInsert() 插入一个TCB 到就绪列表
OS_RdyListInsertHead() 插入一个TCB 到就绪列表的头部
OS_RdyListInsertTail() 插入一个TCB 到就绪列表的尾部
OS_RdyListMoveHeadToTail() 将TCB 从列表的头部移到尾部
OS_RdyListRemove() 将TCB 从就绪列表中移除
假定uC/OS-III 内部的任务都被使能。图6-5 显示了当OSInit()被调用后的就绪列表


Entries=1,表示有一个任务,当某个优先级中只有一个任务的时候,它的头指针和尾指针会指向同一个TCB
uC/OS-III 允许多个任务有相同的优先级。特别的,时基任务的优先级要高于定时器任务,定时器任务的优先级需要于统计任务。

三 添加任务到就绪队列

uC/OS-III 提供很多服务可以把任务添加到就绪列表中。最明显的服务是OSTaskCreate(),它通常创建准备运行的任务并将任务放入就绪列表中。如图6-6 所示,就绪列表中该优先级中已经有两个任务了。OSTaskCreate()就会将这个任务插入到列表的未部。



(1)在调用OSTaskCreate()之前,已经有两个任务在就绪列表中的该优先级中了。
(2)一个新的TCB 传递给OSTaskCreate(),然后uC/OS-III 初始化这个TCB。
(3)OSTaskCreate()调用OS_RdyListInsertTail(),OS_RdyListInsertTail()的作用是将新添加进来的TCB 链接到就绪队列中对应优先级记录(需设置四个指针,就绪列表中两个,任务重两个,并将记录中的.Entries 的值加一)。OSTaskCreate()还会调用OS_PrioInsert()设置位映像表中的相应位。然而,处理OS_PrioInsert()是非常快的,它不会影响到应用的性能。当一个任务创建了一个具有相同优先级的任务,这个新任务会被添加到该优先级队列的尾部(因为具有相同优先级情况下,没有理由让新任务先运行)。然而,当一个任务创建了一个具有不同优先级的任务时,这个新的任务就会放到对应优先级列表中的首部。

四  总结

uC/OS-III 支持任意数量的优先级。然而,绝大多数系统的需求量不会超过64 种。就绪队列包含两个数据结构:位映像表保存了哪个优先级中有任务待运行,优先级列表中包含了这该优先级下等待运行的任务。处理器支持清零指令CLZ 会加快位映像表的扫描速度。{注意:正在运行的任务也被放在就绪列表中。}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章