您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > uCOS-II中的任务管理
2020/12/21μC/OS-II中的任务管理2020/12/22任务的状态及其转换正在运行的任务,需要等待一段时间或需要等待一个事件发生再运行时,该任务就会把CPU的使用权让给别的任务而使任务进入等待状态,利用等待函数OSTimeDly()等实现。任务在没有被配备任务控制块或被剥夺了任务控制块时的状态叫做任务的睡眠状态系统为任务配备了任务控制块且在任务就绪表中进行了就绪登记,这时任务的状态叫做就绪状态。处于就绪状态的任务如果经调度器判断获得了CPU的使用权,则任务就进入运行状态一个正在运行的任务一旦响应中断申请就会中止运行而去执行中断服务程序,这时任务的状态叫做中断服务状态2020/12/23前面谈到,一个任务的任务控制块的主要作用就是保存该任务的虚拟处理器的堆栈指针寄存器SP。其实,随着任务管理工作的复杂性的提高,它还应该保存一些其他信息。任务控制块——任务在系统中的身份证由于系统存在着多个任务,于是系统如何来识别并管理一个任务就是一个需要解决的问题。识别一个任务的最直接的办法是为每一个任务起一个名称。由于μC/OS-II中的任务都有一个惟一的优先级别,因此μC/OS-II是用任务的优先级来作为任务的标识的。所以,任务控制块还要来保存该任务的优先级别。另外,前面也谈到,一个任务在不同的时刻还处于不同的状态,显然,记录了任务状态的数据也应该保存到任务控制块中。基于上述原因,系统必须为每个任务创建一个保存与该任务有关的相关信息的数据结构,这个数据结构就叫做该任务的任务控制块(TCB)。任务控制块结构的主要成员typedefstructos_tcb{OS_STK*OSTCBStkPtr;//指向任务堆栈栈顶的指针……INT8UOSTCBStat;//任务的当前状态标志INT8UOSTCBPrio;//任务的优先级别……}OS_TCB;任务控制块是不是像我们人在一个国家中的身份证?(其实,系统中的所有资源都应该有身份证。)2020/12/24任务在内存中的结构2020/12/25用户任务代码的一般结构voidMyTask(void*pdata){for(;;){可以被中断的用户代码;OS_ENTER_CRITICAL();//进入临界段(关中断)不可以被中断的用户代码;OS_EXIT_CRITICAL();//退出临界段(开中断)可以被中断的用户代码;}}临界段无限循环于是可以这样说,μC/OS-II任务的代码结构是一个可以带有临界段的无限循环。2020/12/26系统提供的空闲任务在多任务系统运行时,系统经常会在某个时间内无用户任务可运行而处于所谓的空闲状态,为了使CPU在没有用户任务可执行的时候有事可做,μC/OS-II提供了一个叫做空闲任务OSTaskIdle()的系统任务voidOSTaskIdle(void*pdata){#ifOS_CRITICAL_METHOD==3OS_CPU_SRcpu_sr;#endifpdata=pdata;//防止某些编译器报错for(;;){OS_ENTER_CRITICAL();//关闭中断OSdleCtr++;//计数OS_EXIT_CRITICAL();//开放中断}}空闲任务只是做了一个计数工作注意!空闲任务中没有调用任务延时函数μC/OS-II规定,一个用户应用程序必须使用这个空闲任务,而且这个任务是不能用软件来删除的2020/12/27系统提供的另一个任务——统计任务μC/OS-II提供的另一个系统任务是统计任务OSTaskStat()。这个统计任务每秒计算一次CPU在单位时间内被使用的时间,并把计算结果以百分比的形式存放在变量OSCPUsage中,以便应用程序通过访问它来了解CPU的利用率,所以这个系统任务OSTaskStat()叫做统计任务2020/12/28任务的优先权及优先级别μC/OS_II把任务的优先权分为64个优先级别,每一个级别都用一个数字来表示。数字0表示任务的优先级别最高,数字越大则表示任务的优先级别越低用户可以根据应用程序的需要,在文件OS_CFG.H中通过给表示最低优先级别的常数OS_LOWEST_PRIO赋值的方法,来说明应用程序中任务优先级别的数目。该常数一旦被定义,则意味着系统中可供使用的优先级别为:0,1,2,……,OS_LOWEST_PRIO,共OS_LOWEST_PRIO+1个固定地,系统总是把最低优先级别OS_LOWEST_PRIO自动赋给空闲任务。如果应用程序中还使用了统计任务,系统则会把优先级别OS_LOWEST_PRIO-1自动赋给统计任务,因此用户任务可以使用的优先级别是:0,1,2…OS_LOWEST_PRIO-2,共OS_LOWEST_PRIO-1个2020/12/29任务堆栈保存CPU寄存器中的内容及存储任务私有数据的需要,每个任务都应该配有自己的堆栈,任务堆栈是任务的重要的组成部分在应用程序中定义任务堆栈的栈区非常简单,即定义一个OS_STK类型的一个数组并在创建一个任务时把这个数组的地址赋给该任务就可以了。例如://定义堆栈的长度#defineTASK_STK_SIZE512//定义一个数组来作为任务堆栈OS_STKTaskStk[TASK_STK_SIZE];typedefunsignedintOS_STK;//这是系统定义的一个数据类型voidmain(void){……OSTaskCreate(MyTask,//任务的指针&MyTaskAgu,//传递给任务的参数&MyTaskStk[MyTaskStkN-1],//任务堆栈栈顶地址20//任务的优先级别);……}在创建用户任务时,要传递任务的堆栈指针和任务优先级别使用函数OSTaskCreate()创建任务时,一定要注意所使用的处理器对堆栈增长方向的支持是向上的还是向下的2020/12/210任务堆栈的初始化应用程序在创建一个新任务的时候,必须把在系统启动这个任务时CPU各寄存器所需要的初始数据(任务指针、任务堆栈指针、程序状态字等等),事先存放在任务的堆栈中μC/OS-II在创建任务函数OSTaskCreate()中通过调用任务堆栈初始化函数OSTaskStkInit()来完成任务堆栈初始化工作的它的原型如下:OS_STK*OSTaskStkInit(void(*task)(void*pd),void*pdato,OS_STK*ptos,INT16Uopt);由于各种处理器的寄存器及对堆栈的操作方式不尽相同,因此该函数需要用户在进行μC/OS-II的移植时,按所使用的处理器由用户来编写。实现这个函数的具体细节,将在本书有关μC/OS-II移植的章节中做进一步的介绍其实,任务堆栈的初始化就是对该任务的虚拟处理器的初始化(复位)。2020/12/211任务控制块(OS_TCB)及任务控制块链表μC/OS-II用来记录任务的堆栈指针、任务的当前状态、任务的优先级别等一些与任务管理有关的属性的表就叫做任务控制块任务控制块就相当于是一个任务的身份证,没有任务控制块的任务是不能被系统承认和管理的任务控制块结构的主要成员typedefstructos_tcb{OS_STK*OSTCBStkPtr;//指向任务堆栈栈顶的指针……structos_tcb*OSTCBNext;//指向后一个任务控制块的指针structos_tcb*OSTCBPrev;//指向前一个任务控制块的指针……INT16UOSTCBDly;//任务等待的时限(节拍数)INT8UOSTCBStat;//任务的当前状态标志INT8UOSTCBPrio;//任务的优先级别……}OS_TCB;任务控制块链表空任务控制块链表当应用程序调用函数OSTaskCreate()创建一个任务时,这个函数会调用系统函数OSTCBInit()来为任务控制块进行初始化。这个函数首先为被创建任务从空任务控制块链表获取一个任务控制块,然后用任务的属性对任务控制块各个成员进行赋值,最后再把这个任务控制块链入到任务控制块链表的头部当进行系统初始化时,初始化函数OSInit();会按用户提供的任务数为系统创建具有相应数量的任务控制块并把它们链接为一个链表。由于这些任务控制块还没有对应的任务,故这个链表叫做空任务块链表。即相当于是一些空白的身份证。2020/12/212任务就绪表及任务调度多任务操作系统的核心工作就是任务调度。所谓调度,就是通过一个算法在多个任务中确定该运行的任务,做这项工作的函数就叫做调度器。μC/OS_II进行任务调度的思想是“近似地每时每刻总是让优先级最高的就绪任务处于运行状态”。为了保证这一点,它在系统或用户任务调用系统函数及执行中断服务程序结束时总是调用调度器,来确定应该运行的任务并运行它。μC/OS_II进行任务调度的依据就是任务就绪表为了能够使系统清楚地知道,系统中哪些任务已经就绪,哪些还没有就绪,μC/OS_II在RAM中设立了一个记录表,系统中的每个任务都在这个表中占据一个位置,并用这个位置的状态(1或者0)来表示任务是否处于就绪状态,这个表就叫做任务就绪状态表,简称叫任务就绪表任务就绪表就是一个二维数组OSRdyTbl[]2020/12/213为加快访问任务就绪表的速度,系统定义了一个变量OSRdyGrp来表明就绪表每行中是否存在就绪任务。2020/12/214OSRdyTbl[]1/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/0OSRdyGrpD7D6D5D4D3D2D1D01/01/01/01/01/01/01/01/0任务就绪表的示意图01234567xy012345672020/12/215OSRdyGrpD7D6D5D4D3D2D1D011110000prio=29D7D6D5D4D3D2D1D01D7D6D5D4D3D2D1D01OSRdyTbl[3]把prio为29的任务置为就绪状态YXOSRdyGrp|=OSMapTbl[prio3];OSRdyTbl[prio3]|=OSMapTbl[prio&0x07];在程序中,可以用类似下面的代码把优先级别为prio的任务置为就绪状态:OSRdyGrp|=OSMapTbl[prio3];OSRdyTbl[prio3]|=OSMapTbl[prio&0x07];如果要使一个优先级别为prio的任务脱离就绪状态则可使用如下类似代码:if((OSRdyTbl[prio3]&=~OSMapTbl[prio&0x07])==0)OSRdyGrp&=~OSMapTbl[prio3];352020/12/216OSRdyGrpD7D6D5D4D3D2D1D011110000prio=29D7D6D5D4D3D2D1D01D7D6D5D4D3D2D1D01OSRdyTbl[y]x=OSUnMapTal[OSRdyTbl[y]];11000000000000y=OSUnMapTal[OSRdyGrp];图5-6在就绪表中查找最高优先级别任务的过程从任务就绪表中获取优先级别最高的就绪任务可用如下类似的代码:y=OSUnMapTal[OSRdyGrp];//D5、D4、D3位x=OSUnMapTal[OSRdyTbl[y]];//D2、D1、D0位prio=(y3)+x;//优先级别或y=OSUnMapTbl[OSRdyGrp];prio=(INT8U)((y3)+OSUnMapTbl[OSRdyTbl[y]]);2020/12/217优先级判定表OSUnMapTbl[256](os_core.c)INT8UconstOSUnMapTbl[]={0,0,1,0,2,0,1,0,3,0,1,0,2,0
本文标题:uCOS-II中的任务管理
链接地址:https://www.777doc.com/doc-7282272 .html