ucosiii任务管理相关知识

摘要:
只要学习和理解:任务状态任务堆栈任务控制块任务就绪表任务调度和切换关于任务状态:任务堆栈是任务的重要部分,堆栈是在RAM中按照“先进先出”的原则组织的一块连续的内存空间。为了满足任务切换和相应中断时保存CPU寄存器中的内容及任务调用其他函数时的需要,每个任务都应该有自己的堆栈。

只要学习和理解:任务状态

任务堆栈

任务控制块

任务就绪表

任务调度和切换

关于任务状态:

ucosiii任务管理相关知识第1张

任务堆栈是任务的重要部分,堆栈是在RAM中按照“先进先出(FIFO)”的原则组织的一块连续的内存空间。为了满足任务切换和相应中断时保存CPU寄存器中的内容及任务调用其他函数时的需要,每个任务都应该有自己的堆栈。

1、任务堆栈的创建:

UCOSIII中任务堆栈的创建很简单,如原子系列教程中的例子:

ucosiii任务管理相关知识第2张

注意:任务堆栈的大小不是512字节,真实大小是下面那个数组所占空间的大小,其中,“CPU_STK”为CPU_INT32U类型(“unsigned int”类型),为4字节的,那么任务堆栈START_TASK_STK的大小就是:512*4=2048字节!

上面是任务堆栈大小相关的部分,那么如何使用那个创建好的堆栈空间呢“

2、任务堆栈的初始化:

任务如何才能切换回上一个任务并且还能继续从上次被中断的地方开始运行呢?那就要恢复现场,现场就是CPU的内部各个寄存器。在刚创建一个新任务时,就必须把系统启动这个任务时所需的CPU各个寄存器的初始值事先存放在任务堆栈中。这样当任务获得CPU使用权时,就把任务堆栈的内容复制到CPU的各个寄存器,从而可以让任务顺利的启动并运行。

2.1、任务堆栈初始化函数:

OSTaskStkInit();

此函数在UCOSIII源码”os_cpu_c.c“中大概229-263行;

函数原型:

CPU_STK *OSTaskStkInit(OS_TASK_PTR    p_task,

void         *p_arg,

CPU_STK       *p_stk_base,

CPU_STK       *p_stk_Limit,

CPU_STK_SIZE   stk_size,

OS_OPT       opt)

注意:*用户一般不会直接操作这个函数,这个函数一般是由”OSTaskCreate()“函数调用;

*不同CPU对寄存器的操作方式不同,因此在移植UCOSIII时需要用户根据自己所选的CPU来编写任务堆栈初始化函数;(这会回想一下,这对应了之前看原子视频的UCOSII移植部分中对文件做出的各种修改的原因)

3、之前创建出来的任务堆栈如何使用:

创建出来的任务堆栈其实是作为任务创建函数”OSTaskCreate()“的参数直接带入即可;

4、任务堆栈栈深:

在“OSTaskCreate()”函数中的第7个参数中,这个参数是任务堆栈栈深的设置;

栈深就是说,任务在使用堆栈时,给他设定一个“堆栈快要用光”的限位,一般限制在堆栈大小的10%,具体先不要纠结这个参数,我想应该是系统需要根据这个数做出什么反应之类。

5、任务控制块:

任务控制块是用来记录与任务相关的信息的数据结构,每个任务都要有自己的控制块。任务控制块有用户自行创建,如下

代码为创建一个任务控制块:

OS_TCB  StartTaskTcb;//创建一个任务控制块

OS_TCB是一个结构体,描述了任务控制块,任务控制块中的成员变量用户不能直接访问,更不可能改变他们。

OS_TCB作为一个结构体,其中有些成员采用了条件编译的方式来确定。

这部分代码在UCOSIII源码“os.h”中大概第939-1045行,这个结构体里面的变量是非常多的;

这个结构体中的变量的详细讲解在原子的资料“STM32 UCOS开发手册.pdf”中第5章,“任务控制块”中;

5.1、任务控制块的初始化:

在前面“OSTaskCreate()”创建任务时,会对任务的任务控制块进行初始化。函数“OS_TaskInitTCB()”用于初始化任务控制块,用户不需要自行初始化任务控制块;

函数“OS_TaskInitTCB()”源码在UCOSIII源码“os_task.c”中大概第1957-2082行;

6、UCOSIII任务就绪表:

6.1优先级

UCOSIII中任务优先级数由宏“OS_CFG_PRIO_MAX”来配置,UCOSIII中数值越小,优先级越高,最低可用优先级就是“OS_CFG_PRIO_MAX-1”;

“OS_CFG_PRIO_MAX”这个宏在UCOSIII源码“os_cfg.h”中大概第48行;(源码中,这个宏默认是64,用户可自由修改,理论上可以无限大)

6.1就绪表

所谓就绪表,就是有个任务已经准备好了,就等着运行了,如果自己的优先级够高,那么下一个运行的任务就是它了;

UCOSIII就绪表中有两部分组成:

1、优先级位映射表:OSPrioTb1[]:用来记录哪个优先级下有任务就绪;

这个表在“os_prio.c”中有定义,大概41行处:

ucosiii任务管理相关知识第3张

2、就绪任务列表:OSRdyList[]:用来记录每一个优先级下所有就绪的任务;

3、下表好好理解理解:

ucosiii任务管理相关知识第4张

6.3 系统如何找到已经就绪了的最高优先级的任务?

函数 "OS_PrioGetHighest()"用于找到就绪了的最高优先级的任务;

源码在“os_prio.c”大概第85行处;

这个函数的作用就是找出最高优先级的任务,找最高优先级时是硬件执行的,速度很快,基本原理如下:

ucosiii任务管理相关知识第5张

函数会一直循环的找“1”,OSPrioTbl[0]里面如果每个位都为0,那就继续往OSPrioTbl[1]中找,直到碰到“1”,就算是找出来了当前已经就绪了的最高优先级的任务,但是此时还不能找到具体哪个任务,因为一个优先级下面有多个任务;

6.4就绪任务列表

刚才上边说了,找到最高优先级后,还不能确定具体是哪个任务,这时就用到就绪任务列表“OSRdyList[]”(上边提到过)了;

在这个列表中,系统会找出最先需要执行的任务,具体要执行哪一个,是按照这个里面的一个链表执行的,最先执行的是链表头那个任务,执行完后就插到尾去了,具体细节先不要过分研究;

7、任务调度和切换

7.1

任务调度就是中止当前正在运行的任务转而去执行其他任务。

UCOSIII是可剥夺型内核,因此当一个高优先级的任务准备就绪,并且此时发生了任务调度,那么这个高优先级的任务就会获得CPU的使用权!

UCOSIII中的任务调度是由任务调度器来完成的,任务调度器有2中:任务级调度器中断级调度器

任务级调度器,是个函数:“OSSched()”;,此函数是在普通任务中使用;

中断级调度器,是个函数:“OSIntExit()”,当在退出外部中断服务函数的时候会使用中断级任务调度,这个函数一般写在中断服务函数里面;

任务调度器使用方法,在原子视频第8讲,UCOSIII任务管理(下)中的第6分左右,有使用方法的说明,就是上边两个函数只要调用一次,系统就会发生一次任务切换;

7.2 任务调度点:

任务调度点就是发生任务调度的时间点或者说节点,就是在哪个地方发生的任务调度;(用户可以自己调用一下调度函数来发生任务调度)

那么,都有哪些任务调度点呢:

ucosiii任务管理相关知识第6张

ucosiii任务管理相关知识第7张

7.3 调度器的上锁和解锁

有时候我们不希望发生任务调度,因为有些时候是不能被打断的,比如正在初始化某个外设的时候,这时就需要对调度器上锁,上锁函数:“OSSchedLock()”;当想要恢复调度器的时候,就需要解锁,解锁函数:“OSSchedUnlock()”;

7.4 时间片轮转调度

ucosiii任务管理相关知识第8张

因为有多任务,每个任务执行指定的时间片,然后轮到下一个任务执行,这个过程就是时间片轮转调度。时间片轮转调度器:“OS_SchedRoundRobin()”;

注意:任务可以放弃自己的时间片,比如一个任务本来要执行4个时间片,执行3个时间片后,出于某种原因,不想继续执行,此时它是可以放弃剩余1个时间片的;

7.5 任务切换

ucosiii任务管理相关知识第9张

上边两个函数在汇编文件“os_cpu_a.asm”中

注:任务切换是包含在任务调度中的;

8、UCOSIII系统初始化:

在使用UCOSIII之前我们必须先初始化UCOSIII,函数“OSIniy()”用来完成UCOSIII的初始化,而且OSInit()必须先于其它UCOSIII函数调用,包括OSStart()。

9、UCOSIII系统启动:

使用函数"OSStart()"来启动UCOSIII;

免责声明:文章转载自《ucosiii任务管理相关知识》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇矿产资源储量动态监管服务零拷贝下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android开发 -- Bootloader

本文转载自:http://blog.csdn.net/jmq_0000/article/details/7378348 LK是什么            LK 是 Little Kernel 它是 appsbl (Applications ARM Boot Loader)流程代码  ,little kernel 是小内核小操作系统。           ...

现代操作系统 第一章 引论 笔记

现代操作系统 封面上的趣图 什么是计算机系统? 现代计算机系统由一个或多个处理器、主存、磁盘、打印机、键盘、鼠标、显示器、网络接口以及各种其他输入/输出设备组成。 什么是操作系统? 操作系统是一个软件,它的任务是为用户程序提供一个更好、更简单、更清晰的计算机模型,并管理组成计算机系统的各种设备。 操作系统的两个功能? 1. 扩展机器(自顶向下的观点)...

ARM参数传递规则

1.       r0,r1,r2,r3,在调用函数时,用来存放前4个函数参数和返回值,r4-r11,r14,在调用函数时必须保存这些寄存器到堆栈当中。如果函数的参数多于4个,则多余参数存放在堆栈当中,即sp,sp+4,sp+8,…依次类推。   2.       函数内部通用的入栈出栈代码可以为: STMFD sp!,{r4-r11,lr} // bod...

java进程占用CPU高的问题

一. 上节回顾怎么查看CPU使用率? top:显示了系统总体的CPU和内存使用情况,以及各个进程的资源使用情况。默认每隔3s刷新一次 ps:只显示每个进程的资源使用情况 top并没有细分进程的用户态CPU和内核态CPU pidstat:可以分析每个进程的CPU使用情况 通过top,ps,pidstat这些工具,能够很快找到CPU使用率较高的进程。要知道CP...

Windows:任务调度器

Windows 服务器系列: Windows:查看IP地址,IP地址对应的机器名,占用的端口,以及占用该端口的应用程 Windows:使用Dos命令管理服务(Services) Windows:任务调度器 Windows:打开MSDTC,恢复Windows任务栏,查看windows日志,打开远程桌面,打开Services,资源监控 任务调度程序是一个非...

为代码编写稳定的单元测试 [Go]

为代码编写稳定的单元测试 本文档配套代码仓库地址: https://github.com/liweiforeveryoung/curd_demo 配合 git checkout 出指定 commit 以及 git diff 比较 commit 间的差别食用更佳 单元测试的作用 功能交付的保障,确保不会发生一些低级错误,只要你觉得哪处逻辑在某种 case...