资源描述
单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,单击此处编辑母版标题样式,C/OS-II,操作系统中进程调度模块分析,背 景,1,、课程任务:,分析,C/OS-II,操作系统中的进程调度模块的源代码,2,、任务说明:结合课堂上讲授的进程的定义、进程控制块、进程的创建以及处理机调度算法等知识点,分析,C/OS-II,操作系统中的进程调度模块的源码实现。进而理解进程控制块的结构,理解进程运行的并发性,掌握进程调度的方法。,3,、任务要求:,(,1,)熟悉相关的理论知识;,(,2,)分析,C/OS-II,操作系统中的进程调度模块的代码实现,并辅以图表的形式描述实现流程;,(,3,)对核心代码作注释说明。,(,4,)按照模板撰写分析报告,以小组为单位参加答辩。,1,、,uC/OS,的任务控制块,-0.8 (25,页,2.3 ),2,、任务就绪表的结构,-0.9 (29,页,2.4.1),3,、对任务就绪表的操作(将就绪任务状态填入就绪表),-0.9,(31,页,2.4.2),4,、根据就绪表确定最高优先级(采用查表法确定高优先级任务),-1,(,31,页,2.4.2),5,、任务调度器实现流程图表述,-1,(,43,页,2.4.3,),6,、任务调度器实现及源代码分析,-1,(,43,页,2.4.3,),7,、任务切换的过程描述,-0.8,(可选)(,43,页,2.4.3,),8,、用户任务的实现(编写一个示例程序验证调度算法),-1,(,43,页例,2-7,),9,、任务状态切换(挂起和恢复任务)示例程序演示,-0.9,(可选),(,48,页例,2-8,),10,、用信号量实现任务间同步和互斥示例程序演示,-0.9,(可选),(,119,页例,4-4,,,122,页例,4-5,),11,、用消息邮箱实现任务间通信示例程序演示,-0.9,(可选)(,136,页例,4-8,),任 务,实时操作系统,C/OS-II,1,3,2,C/OS-II,概述,任务概念,任务调度核心问题分析,C/OS,简介,美国人,Jean Labrosse 1992,年完成,应用面覆盖了诸多领域,如照相机、医疗器械、音响设备、发动机控制、高速公路电话系统、自动提款机等,1998,年,C/OS,-II,,目前的版本,C/OS,-II V2.61,,,2.72,2000,年,得到美国航空管理局(,FAA,)的认证,可以用于飞行器中,网站,www.ucos-II.com,(,),数 据 类 型,typedef unsigned char,INT8U,;,typedef signed char,INT8S,;,typedef unsigned int,INT16U,;,typedef signed int,INT16S,;,typedef unsigned long,INT32U,;,typedef signed long,INT32S,;,typedef float,FP32,;,typedef double,FP64,;,实时操作系统,C/OS-II,1,3,2,C/OS-II,概述,任务概念,任务调度核心问题分析,任务调度概念,任务控制块,任务代码结构,任务优先级,一个任务的实现,任务控制块,TCB,一旦任务建立,一个任务控制块,OS_TCB,就被赋值。,任务控制块是一个数据结构,保存该任务的相关参数,包括任务堆栈指针,任务的当前状态,任务的优先级等。,任务,CPU,使用权被剥夺时,,TCB,保存该时刻任务状态;任务重新得到,CPU,控制权时,,TCB,确保任务从当时被中断的那一点丝毫不差地继续执行。,OS_TCB,全部驻留在,RAM,中。,任务控制块就相当于一个任务的身份证,没有任务控制块的任务是不能被系统承认和管理的。,PCB,:标识符、父进程标识符、程序计数器、栈指针、,进程状态、优先级,任务控制块,TCB,uCOS_II.H,第,370,行,typedef,struct,os_tcb,OS_STK *OSTCBStkPtr;/,指向任务堆栈栈顶的指针,struct os_tcb*OSTCBNext;/,指向后一个任务控制块的指针,struct os_tcb*OSTCBPrev;/,指向前一个任务控制块的指针,INT16U OSTCBDly;/,任务等待的时限(节拍数),INT8U OSTCBStat;/,任务的当前状态标志,INT8U OSTCBPrio;/,任务的优先级别,OS_TCB;,任务控制块链表,空任务块链表,OSTCBNext,OSTCBPrev,OSTCBPrio,OSTCBNext,OSTCBPrev,OSTCBPrio,OSTCBNext,OSTCBPrev,OSTCBPrio,OSTCBNext,OSTCBPrev,OSTCBPrio,OSTCBTbl0,OSTCBTbl1,OSTCBTblOS_MAX_TASKS+OS_N_SYS_TASK_-2,OSTCBTblOS_MAX_TASKS+OS_N_SYS_TASK_-1,OSTCBFreeList,系统在调用函数,OSInit(),对,uC/OS-II,系统进行初始化时,先在,RAM,中建立一个,OS_TCB,结构类型的数组,OSTCBTbl,每个数组元素就是一个任务控制块,然后把这些控制块链接成一个如图所示的链表。由于链表中的这些控制块还没有与具体任务相关联,因此这个链表叫做空任务块链表。,每当应用程序调用系统函数,OSTaskCreate(),创建一个任务时,系统就会将任务控制块链表头指针,OSTCBFreeList,指向的任务控制块分配给该任务。在给任务控制块中的各成员赋值后,就按任务控制块链表的头指针,OSTCBList,将其加入到任务控制块链表中。,uC/OS,的任务,uC/OS-II,的任务有两种:用户任务和系统任务。由应用程序设计者编写的任务叫做用户任务,由系统提供的任务叫做系统任务。用户任务是为解决应用问题而编写的,系统任务是为应用程序来提供某种服务的。,目前,,uC/OS-II,最多可以对,64,个任务(包括用户任务和系统任务)进行管理。,空闲任务和统计任务,内核总是创建一个,空闲任务,OSTaskIdle(),;,总是设置为最低优先级,,OS_LOWEST_PRIOR,;,当所有其他任务都未在执行时,空闲任务开始执行;,应用程序不能删除该任务;,空闲任务的工作就是把,32,位计数器,OSIdleCtr,加,1,,该计数器被统计任务所使用;,统计任务,OSTaskStat(),,提供运行时间统计。每秒钟运行一次,计算当前的,CPU,利用率。其优先级是,OS_LOWEST_PRIOR-1,,可选。,任务的优先级,uC/OS-II,分为,64,个优先级别,每一个级别都用一个数字表示。数字,0,的级别最高,数字越大优先级别越低。,通常,一个应用程序的任务数小于,64,,用户可根据应用程序的需要,在,OS_CFG.H,中设置,OS_LOWEST_PRIO,,即定义了可供使用的优先级别共,OS_LOWEST_PRIO+1,个。,固定地,系统总是把最低优先级别自动赋给空闲任务,如果系统中还有统计任务,则其优先级别为,OS_LOWEST_PRIO-1,。,任务的优先级同样也是它的标识号,ID,。,问题,1:,如果创建,2,个相同优先级的任务会怎么执行?,任务的实现,创建任务的系统服务,OSTaskCreate(),INT8U OSTaskCreate(void(*task)(void*pd),/,任务代码指针,void*pdata,/,任务参数指针,OS_STK*ptos,/,任务栈的栈顶指针,INT8U prio /,任务的优先级,);,用户任务代码的一般结构,void MyTask(void*pdata),for(;),可以被中断的任务代码;,OS_ENTER_CRITICAL();,/,进入临界段(关中断),不可以被中断,的任务代码;,OS_EXIT_CRITICAL();/,退出临界段,(,开中断,),可以被中断的任务代码;,OSTimeDly(10);,根据嵌入式系统任务的工作特点,任务的执行代码通常是一个无限循环结构,并且在这个循环中可以响应中断,这种结构也叫超循环结构。,为了有效的对中断进行控制,在任务的代码里可使用,UC/OS-II,定义的宏,OS_ENTER_CRITICAL(),和,OS_EXIT_CRITICAL(),来控制何时响应中断,何时屏蔽中断。在运行这两个宏之间的代码时是不会响应中断的,这种受保护的代码段叫临界段。,用户应用程序一般结构,(,续,),void Task1(void*pdata)/,定义用户任务,1,for(;),void Task2(void*pdata)/,定义用户任务,2,for(;),void main(),OSInit();/,初始化,uC/OS-II,OSTaskCreate(Task1,);/,创建用户任务,1,OSTaskCreate(Task2,);/,创建用户任务,2,OSStart();/,启动任务,是一个任务。因此它不是被主函数或其它函数调用的,主函数,main(),只负责,创建和启动它们,,而由操作系统负责来,调度运行它们,。,使用函数,OSStart(),启动任务之后,任务就交由操作系统管理和调度了。,一个具体的应用任务实例,代码,实时操作系统,C/OS-II,1,3,2,C/OS-II,概述,任务概念,任务调度核心问题分析,多任务操作系统的核心:,任务调度,。,调度定义:就是通过一个算法在多个任务中确定哪个任务来运行。做这项工作的就是,调度器,。,调度器的主要工作:一是在任务就绪表中查找具有最高优先级别的就绪任务;二是实现任务的切换。,调度算法:可抢占的高优先级调度算法,调度条件:它在系统或用户任务调用系统函数及执行中断服务程序结束时来调用调度器,以确定该运行的任务并运行它。,uC/OS-II,进行任务调度的依据:,任务就绪表,。,就绪任务表及任务调度,为了能使系统清楚地知道系统中哪些任务已经就绪,哪些还没有就绪,,UC/OS-II,在,RAM,中设立了一个记录表,系统中的每个任务都在这个表占据一个位置,并用这个位置的状态(,1,或者,0,)来表示任务是否处于就绪状态。这个表就叫做任务就绪表。,C/OS,任务调度器实现及源代码分析,void OSSched(void),INT8U y;,OS_ENTER_CRITICAL();,if(OSLockNesting|OSIntNesting)=0),y =OSUnMapTblOSRdyGrp;,OSPrioHighRdy=(INT8U)(y 3;,OSRdyTblprio3|=OSMapTblprio,其中,,OSMapTbl,是,uC/OS-II,为加快运算速度定义的一个数组,各元素为:,OSMapTbl0=0000 0001B,OSMapTbl1=0000 0010B,OSMapTbl2=0000 0100B,OSMapTbl3=0000 1000B,OSMapTbl4=0001 0000B,OSMapTbl5=0010 0000B,OSMapTbl6=0100 0000B,OSMapTbl7=1000 0000B,如果要使一个优先级为,prio,的任务脱离就绪态,则可使用如下代码:,If(OSRdyTblprio3&=,OSMapTblprio&0 x07)=0),OSRdyGrp&=,OSMapTblprio3;,脱离就绪态:将任务就绪表,OSRdyTblprio3,相应元素的相应位清零,而且当,OSRdyTblprio3,中的所有位都为零时,即全组任务中没有一个进入就绪态时,,OSRdyGrp,的相应位才为零。,对任务就绪表的操作,(,续,),例:欲使,优先级为,12,的任务进入就绪态,设置就绪表。,答:优先级为,12,,即,00001100B,。,OSRdyGrp|=,OSMapTblprio3,;,(,OSMapTbl1=0000 0010,),OSRdyTbl1|=,OSMapTblprio&0 x07,;,(,OSMapTbl4=0001 0000,),例:欲使,优先级为,12,的任务脱离就绪态,设置就绪表。,答:优先级为,12,,即,00001100B,。,OSMapTblprio&0 x07=,OSMapTbl4=11101111,OSMapTblprio3=,OSMapTbl1=11111101,如果,OSRdyTblprio3&=,OSMapTblprio&0 x07=0,(该行所有任务都是非就绪态),则,OSRdyGrp=OSRdyGrp&,OSMapTblprio3=0,问题,2,:优先级为,22,的任务进入,/,脱离就绪态,根据就绪表确定最高优先级,两个关键,:,将优先级数,分解,为高三位和低三位分别确定;,高优先级有着小的优先级号;,从任务就绪表中获取优先级别最高的就绪任务可用如下代码:,采用查表法确定高优先级任务,Y=,OSUnMapTbl,OSRdyGrp;/,获得优先级别的,D5,、,D4,、,D3,位,X=,OSUnMapTbl,OSRdyTblY;/,获得优先级别的,D2,、,D1,、,D0,位,Prio=(Y3)+X;,/,获得就绪任务的优先级别,其中,,OSUnMapTbl,同样是,uC/OS-II,为加快运算速度定义的一个数组,共有,256,个元素:,INT8U const OSUnMapTbl16*16=,0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,;,举例:,如已知,OSRdyGrp,的值为,01101000B,,即,104,,则查得,OSUnMapTblOSRdyGrp,的值是,3,。,如已知,OSRdyTbl3,的值是,11100100B,,即,228,,则查,OSUnMapTblOSRdyTbl3,的值是,2,。,则进入就绪态的最高任务优先级。,Prio=,(,33,),+2=26,UC/OS-II,经常使用类似于就绪表的形式来记录任务的某种状态,因此一定要熟悉这种表的结构以及对这种表的基本操作。,源代码中使用了查表法,查表法具有确定的时间,增加了系统的可预测性,,uC/OS,中所有的系统调用时间都是确定的,以空间换时间,Y=OSUnMapTblOSRdyGrp;,X=OSUnMapTblOSRdyTblY;,Prio=(Y3)+X;,参,见OS_CORE.C,void OSSched(void),INT8U y;,OS_ENTER_CRITICAL();,if(OSLockNesting|OSIntNesting)=0)(1),y=OSUnMapTblOSRdyGrp;(2),OSPrioHighRdy=(INT8U)(y 3)+OSUnMapTblOSRdyTbly);,if(OSPrioHighRdy!=OSPrioCur)(3),OSTCBHighRdy=OSTCBPrioTblOSPrioHighRdy;(4),OSCtxSwCtr+;(5),OS_TASK_SW();(6),OS_EXIT_CRITICAL();,开始,因处理全局变量而关中断,找出准备就绪且优先级最高的任务,将准备就绪的最高优先级任务指向该任务的控制块,该任务是否为当前运行任务,是否中断嵌套或调度上锁,开中断,调用任务切换函数,任务切换统计数器加,1,结束,任务切换,任务切换的两个步骤:,1.,获得待运行任务的,TCB,指针。,2.,进行断点数据的切换。,任务的调度,(,续,),1.,获得待运行任务的,TCB,指针,void OSSched(void),INT8U y;,OS_ENTER_CRITICAL();,if(OSLockNesting|OSIntNesting)=0)/,未被上锁且不是中断服务程序调用,y =OSUnMapTblOSRdyGrp;,OSPrioHighRdy=(INT8U)(y OSTCBStkPtr=SP;,/,使系统获得待运行任务控制块,OSTCBCur=OSTCBHighRdy,;,/,把待运行任务堆栈指针赋给,SP,SP=OSTCBHighRdy-OSTCBStkPtr;,用出栈指令把,R1,、,R2.,弹入,CPU,的通用寄存器;,2.,任务切换宏,OS_TASK_SW()-,续,任务的调度,(,续,),任务切换过程,获得待运行任务的任务控制块,恢复待运行任务的运行环境,处理器的,PC=,任务堆栈中的断点地址,处理器的,SP=,任务块中保存的,SP,如何获得待运行任务的任务控制块?,根据就绪表获得待运行任务的任务控制块指针,其实,调度器在进行调度时,在这个位置还要进行一下判断:究竟待运行任务是否为当前任务,如果是,则不切换;如果不是才切换,而且还要保存被中止任务的运行环境。,给调度器上锁,OSSchedlock(),:给调度器上锁函数,用于禁止任务调度,保持对,CPU,的控制权(即使有优先级更高的任务进入了就绪态);,OSSchedUnlock(),:给调度器开锁函数,当任务完成后调用此函数,调度重新得到允许;,当低优先级的任务要发消息给多任务的邮箱、消息队列、信号量时,它不希望高优先级的任务在邮箱、队列和信号量还没有得到消息之前就取得了,CPU,的控制权,此时,可以使用调度器上锁函数。,谢 谢,!,
展开阅读全文