任务管理和就绪列表

版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_44880138/article/details/102593552

任务管理 Task management

5.4 任务管理服务

uCOS-III 任务相关函数可以在os_task.c中找到。命名规则OS_Task???()

任务可以简单分为三类 普通任务 标记任务 给任务发送消息的任务。下图有介绍
在这里插入图片描述

任务控制块TCB

任务控制块是被 uC/OS-III 用于维护任务的一个结构体。每个任务都必须有自己的 TCB。uC/OS-III 在 RAM 中分配 TCB。当调用uC/OS-III 提供的与任务相关的函数(以 OSTask???()形式命名)时,任务的 TCB 地址需会被提供给该函数。TCB 的结构定义于 os.h中,(在 OS.H 中代码是有注释的)。TCB 中的一些变量可以根据具体应用进行裁剪。用户程序不应该访问这些变量(尤其不能更改它们)。换句话说,TCB 中的变量只能被 uC/OS-III 访问。
在这里插入图片描述
在这里插入图片描述

内部任务

uC/OS-III 初始化的时候,它会创建至少 2 个内部的任务。一共要有五个任务,五种状态

OS_TickTask() 时基任务  	//必须创建的
OS_IdleTask() 空闲任务	//必须创建的
OS_StatTask() 统计任务	//创建是可选的
OS_TmrTask()  定时器器任务		//创建是可选的
OS_IntQTask() 中断队列处理任务	//创建是可选的
//创建是可选的由OS_CFG.H 中的配置决定
Dormant 	休眠状态
Ready		就绪状态
Running 	运行状态
Pending 	挂起状态
Interrupted 中断状态

空闲任务 OS_IdleTask()

空闲任务的优先级别是最低的,当CPU中没有其他任务在运行的时候才轮到它运行。为了安全起见,它的优先级别是唯一的并且在使用 OS_TaskCreate()创建新任务的时候不能配置和它一样的优先级任务。详细代码看os_core.c 下面是一部分代码
在这里插入图片描述
空闲任务是一个无限循环的不会等待任何事件的任务。这是因为,在大部分的处理器中,当没有事情可做时,处理器依然会执行指令。当 uC/OS-III 中没有其它更高的就绪任务待运行时,uC/OS-III就会把 CPU 分配给空闲任务。

时基任务 OS-TickTask()

几乎所有的实时系统都需要有一个能提供周期性时间的时间源,叫做时基周期或系统周期。uC/OS-III 的时基周期处理程序封装在OS_TICK.C 文件中。OS_TickTask()任务被 uC/OS-III 创建,其优先级是用户可配置的。(通过配置 OS_CFG_APP.H 中的 OS_CFG_TICK_TASK_PRIO)。通常设置其优先级较高。事实上,它的优先级应该设置比重要任务的优先级稍低。OS_TickTask()用于追踪等待期满的任务、挂起超时的任务。OS_TickTask()是一个周期性任务,它等待来自于 ISR 的信号量。

统计任务 OS_StatTask()

这个任务能够统计总的 CPU 使用率(0 到 100%),每个任务的 CPU使用率(0 到 100%),每个任务的堆栈使用量。统计任务在 uC/OS-III 中是可选的,当设置 OS_CFG.H 中的OS_CFG_STAT_TASK_EN1 时,统计任务的代码会被包含在程序中。当然,统计任务的优先级和它的任务堆栈大小在 OS_CFG_APP.H中配置。

定时器任务 OS_TmrTask()

uC/OS-III 为用户提供了定时器任务,相应代码在 OS_TMR.C 中。定时器任务是可选的,通过将 OS_CFG.H 中的 OS_CFG_TMR_EN设置为 1 使能。当设置为 1 时,它的代码才会被添加到最终代码中。当定时器任务递减计数变量到 0 时,任务中就会调用回调函数。

回调函数是一个函数,它被用户定义。因此,回调函数可以用来开启或关闭 LED、电机、或者其他的一些操作。用户可以创建任意个定时器(只限制于处理器的 RAM)。

在创建的时候优先级一般被配置为中等。

中断处理任务 OS_IntQTask()

当设置 OS_CFG.H 中的OS_CFG_ISR_POST_DEFERRED_EN1 时,uC/OS-III 就会创建一个任务,它的作用是尽快完成 ISR 中对post 函数的调用,将信号量、消息等对象先存在媒介中,退出中断后,由中断处理任务完成将这些对象提交给任务。

uC/OS-III 通过开启/关闭中断、锁/开锁调度器管理临界段。如果选择后一种方法,ISR 调用的 post函数不允许直接访问就绪列表、挂起队列等当 ISR 调用 uC/OS-III 提供的 post 函数时,ISR 要提交的数据会被复制,该数据的目的地会被放到一个特殊的队列—"holding"队列。当所有的嵌套中断结束时,uC/OS-III 切换到中断处理任务,它会将放置在"holding"队列中的信息重新提交到适当的任务。这个额外步骤的目的是减小关中断时间。

OS_IntQTak()被 uC/OS-III 创建,它的优先级通常被设为 0(最高优先级)。如果 OS_CFG_ISR_POST_DEFERRED_EN 被设置为 1,使能了这个任务,其它的任务的优先级就不能设置为 0。
在这里插入图片描述

总结任务管理:任务是一段简单的程序。在单 CPU 系统中,任何时间只能有一个任务被 CPU 运行。uC/OS-III 支持多任务并对任务数没有限制(仅限制于 CPU 的存储空间,包括代码空间和数据空间)。

就绪列表The Ready List

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

优先级别

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


优先级相关的常见函数
在这里插入图片描述


就绪表

准备好运行的任务被放到就绪列表中。就绪列表是一个数组(OSRdyList[]),它一共有 OS_CFG_PRIO_MAX 条记录,记录的数据类型为 OS_RDY_LIST(见 OS.H)。就绪列表中的每条记录都包含了三个变量 .Entries 、.TailPtr 、.HeadPtr。.Entries 中该优先级的就绪任务数。当该优先级中没有任务就绪时,.Entries 就会被设置为 0.TailPtr.HeadPtr 用于该优先级就绪任务的建立双向列表。.HeadPtr 指向列表的头部,.TailPtr 指向列表的尾部。表中的记录跟任务的优先级有关。例如,如果一个任务的优先级是 5,那么当它就绪时会被放入 OSRdyList[5]中。
在这里插入图片描述
任务中的指针
.PrevPtr.NextPtr用于指向具有相同优先级到 TCB 组成的双向列表。对于空闲任务,这两个值为 NULL

在这里插入图片描述
如上图所示,时基任务优先级别需要比定时器任务的高(一般情况:时基任务给定时器任务提供时钟源),定时器任务高于统计任务。
当某个优先级中只有一个任务的时候,它的头部指针和尾部指针指向同一个TCB。

添加任务到就绪队列中

uC/OS-III 提供很多服务可以把任务添加到就绪列表中。最明显的服务是OSTaskCreate(),它通常创建准备运行的任务并将任务放入就绪列表中。

情况分两种

情况1 任务所在的该优先级中有就绪任务,则调用OSTaskCreate()调用 OS_RdyListInsertTail()OS_RdyListInsertTail()的作用是将新添加进来的 TCB 链接到就绪队列中对应优先级记录(需设置四个指针,就绪列表中两个,任务重两个,并将记录中的.Entries 的值加一)。

情况2 任务所在的该优先级中没有就绪任务,那么这个新建的任务放到对应优先级中的头部。

就绪列表的总结

uC/OS-III 支持任意数量的优先级。然而,绝大多数系统的需求量不会超过 64 种。

就绪队列包含两个数据结构:位映像表保存了哪个优先级中有任务待运行,优先级列表中包含了这该优先级下等待运行的任务。处理器支持清零指令 CLZ 会加快位映像表的扫描速度。

{注意:正在运行的任务也被放在就绪列表中。}

声明本文参考了
《uC/OS-III 嵌入式系统的翻译》屈环宇
《uC/OS-III the Real-Time Kernel》 Jean.J.Labrosse

猜你喜欢

转载自blog.csdn.net/weixin_44880138/article/details/102593552