UCOSII-详解part3

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

2.6.2OSTaskSuspend流程分析根据对代码的分析,给出流程,如图2.20所示。开始,参数prio为任务优先级是否正确?参数及控制块检查否返回是否是挂起自己?Self=TRUE是是否Self=FALSE在就绪表中删除就绪标志在控制块中的OSTCBStat设置挂起标志Self==TRUE?进行任务调度是否图2.20任务挂起的流程2.6.3OSTaskResume代码解析通过前面两节的学习,可知函数OSTaskSuspend用来暂时停止一个任务的执行,将任务状态转换为阻塞态。那么处于阻塞态的任务要想得到运行,必须先恢复到就绪态。这个恢复被挂起的任务的函数就是OSTaskResume,它和OSTaskSuspend正好是一对函数。在OSTaskSuspend挂起一个任务的时候,要修改就绪表和就绪组,取消任务的就绪标志;那么当恢复一个任务的时候,应该加上就绪标志。另外,对于挂起的标志,是在任务控制块中的OSTCBStat从低到高的第4位,因此,如果恢复一个任务,应该看这一位是否已经被置位,如果没有被置位,那么恢复操作也应该是无效的。最后,如果一切正常,再将该位进行复位。程序2.26给出了OSTaskResume代码的详细解析。嵌入式实时操作系统μC/OS原理与实践程序2.26OSTaskResume代码解析INT8UOSTaskResume(INT8Uprio){OS_TCB*ptcb;#ifOS_ARG_CHK_EN0uif(prio=OS_LOWEST_PRIO){/*检查优先级有效性*/return(OS_ERR_PRIO_INVALID);}#endifOS_ENTER_CRITICAL();ptcb=OSTCBPrioTbl[prio];if(ptcb==(OS_TCB*)0){/*被挂起的任务必须存在*/OS_EXIT_CRITICAL();return(OS_ERR_TASK_RESUME_PRIO);}if(ptcb==OS_TCB_RESERVED){/*控制块是否被保留*/OS_EXIT_CRITICAL();return(OS_ERR_TASK_NOT_EXIST);}if((ptcb-OSTCBStat&OS_STAT_SUSPEND)!=OS_STAT_RDY){/*任务必须是被挂起的才需要恢复*/(1)ptcb-OSTCBStat&=(INT8U)~(INT8U)OS_STAT_SUSPEND;/*移除挂起标志*/(2)if(ptcb-OSTCBStat==OS_STAT_RDY){/*是否就绪了*/(3)if(ptcb-OSTCBDly==0u){/*是否没有延时*/(4)/*设置就绪组和就绪表,使任务就绪*/OSRdyGrp|=ptcb-OSTCBBitY;OSRdyTbl[ptcb-OSTCBY]|=ptcb-OSTCBBitX;OS_EXIT_CRITICAL();if(OSRunning==OS_TRUE){OS_Sched();/*进行一次任务调度*/}}else{OS_EXIT_CRITICAL();}}else{/*必然是在等待事件的发生,因此不能就绪*/OS_EXIT_CRITICAL();}return(OS_ERR_NONE);}OS_EXIT_CRITICAL();return(OS_ERR_TASK_NOT_SUSPENDED);}代码中(1)处为判断要恢复的任务是否为被OSTaskSuspend挂起。当然,如果对应优先级的任务并没有被OSTaskSuspend挂起,就谈不上使用OSTaskResume恢复。将要恢复的任务称为目标任务,目标任务的控制块称为目标TCB,那么,前面将目标任务的TCB的地址已经赋值给了ptcb,目标TCB的OSTCBStat从低到高的第4位标志着任务是否被挂起。而宏OS_STAT_SUSPEND就是二进制的00001000,因此ptcb-OSTCBStat&24第2章任务管理OS_STAT_SUSPEND刚好是屏蔽了OSTCBStat中的所有其他的位,因为&是按位与,只留下了第4位。OS_STAT_RDY的值是0,所以ptcb-OSTCBStat&OS_STAT_SUSPEND的结果不等于0就说明了确实是被OSTaskSuspend挂起的任务。(2)处代码比较奇怪,只是使用了两个强制类型转换,这种强制类型转换是在C语言编程中经常遇到的。(INT8U)OS_STAT_SUSPEND将这个宏强制类型转换为8位的,然后按位取反,再将取反结果强制类型转换为8位无符号整数。之后再与ptcb-OSTCBStat按位与,按位与的结果再赋值给ptcb-OSTCBStat。因为宏OS_STAT_SUSPEND的值应该是二进制的00001000,按位取反后是11110111,因此实现的就是将ptcb-OSTCBStat的表示是否挂起的位清除。那么,在(2)处清除了挂起标志之后,为什么在(3)处还要判断ptcb-OSTCBStat的值是不是0呢?因为任务状态中还含其他的位,如任务可能是因为等待信号量而阻塞的,那么即便清除了挂起标志,OSTCBStat的值还不是0。所以如果这时候还是非0,那么任务肯定还是在等待诸如信号量、邮箱、队列等事件的发生,因此仍然不能就绪。(4)处的ptcb-OSTCBDly是任务控制块中的OSTCBDly域,表示任务延迟的时间。如果OSTCBDly的值不是0,说明任务还在等待时间延时,也不能进入就绪态。2.6.4OSTaskResume流程分析可见,恢复一个被挂起的任务,除了要判断优先级的合法性,还要判断该任务是不是被OSTaskSuspend挂起的任务。除此之外,要恢复被OSTaskSuspend挂起的任务需要的就是清除一位标志,但是是否需要将任务就绪,还需要根据很多的条件进行判断。OSTaskResume的流程如图2.21所示。25嵌入式实时操作系统μC/OS原理与实践开始,参数prio为任务优先级是否正确?参数及控制块检查否返回是否是挂起的任务?取消控制块中OSTCBStat中挂起标志是是否在就绪表中删除就绪标志OSTCBStat中是否有就绪标志且延时时间为0?进行任务调度是否图2.21OSTaskResume的流程2.7任务的调度和多任务的启动通过前面章节的学习,读者应该对内核和任务管理的基本内容有了一定的了解,掌握了任务管理的基本数据结构,学习了很多重要的全局变量,也对任务创建、控制块初始化等关26第2章任务管理键操作系统函数进行了比较细致的学习,并且对堆栈有了比较深入的认识。那么,现在开始学习任务的调度和多任务的启动部分。2.7.1任务调度器μC/OS-II操作系统是实时操作系统,而且是基于优先级调度的实时操作系统,因此在启动多任务以后,每个时钟中断都要执行任务的调度。至于如何实现时钟中断,对不同的硬件环境是不同的,可以自己编写代码实现或在相关网站下载合适的代码。如果时间片是20ms,那么每20ms执行一次任务调度。这个任务调度的函数就是OSTimeTick。OSTimeTick是与硬件无关的,程序2.27给出了OSTimeTick的基本代码解析。程序2.27OSTimeTick基本代码解析voidOSTimeTick(void){OS_TCB*ptcb;OSTimeTickHook();/*调用用户钩子函数,默认是空函数*/OS_ENTER_CRITICAL();/*调度计数器计数加1*/OSTime++;OS_EXIT_CRITICAL();if(OSRunning==OS_TRUE)/*如果已经启动了多任务*/{ptcb=OSTCBList;/*ptcb指向就绪链表表头*/while(ptcb-OSTCBPrio!=OS_TASK_IDLE_PRIO){/*如果该任务非空闲任务*//*就绪链表中的最后一个TCB是空闲任务的*/(1)OS_ENTER_CRITICAL();if(ptcb-OSTCBDly!=0u){/*如果该任务设置了时间延时或事件等待延时*/ptcb-OSTCBDly--;/*延迟时间减1,因为过了1个时钟嘀答/if(ptcb-OSTCBDly==0u){/*检查延迟是否到期了*/if((ptcb-OSTCBStat&OS_STAT_PEND_ANY)!=OS_STAT_RDY)(2){/*如果任务有等待任一事件的发生*//*清等待标志,因为等待时间到了,事件没有发生,不再等待*/ptcb-OSTCBStat&=(INT8U)~(INT8U)OS_STAT_PEND_ANY;ptcb-OSTCBStatPend=OS_STAT_PEND_TO;/*指示事件等待因为超时的原因为结束*/}else{/*如果任务没有等待事件的发生,那么只是简单的延时*/ptcb-OSTCBStatPend=OS_STAT_PEND_OK;/*指示延时时间到了*/27嵌入式实时操作系统μC/OS原理与实践}/*如果任务不是被挂起的*/if((ptcb-OSTCBStat&OS_STAT_SUSPEND)==OS_STAT_RDY){OSRdyGrp|=ptcb-OSTCBBitY;OSRdyTbl[ptcb-OSTCBY]|=ptcb-OSTCBBitX;/*延时时间到了,让任务就绪。如果任务是被挂起的,尽管延时时间到了,也不能就绪,挂起的任务只能用OSTaskResume来恢复到就绪状态*/}}}ptcb=ptcb-OSTCBNext;/*指向下一个TCB*/OS_EXIT_CRITICAL();}}}因为读者还没有学习到事件处理的章节,所以现在完全读懂这段代码稍微有些困难。需要解释的是第(1)处,从操作系统的初始化函数OSInit来看,我们创建的第一个任务是空闲任务。然后每次创建的新任务都是将该任务的TCB插入到就绪链表的表头,而空闲任务不允许被删除。因此,在就绪链表中,最后一个TCB永远是空闲任务的。所以,while循环从就绪链表的表头开始,一直到空闲任务为止,遍历了除空闲任务之外的所有任务。至于(2)处,需要对TCB中的状态标志OSTCBStat更进一步理解,重新将OSTCBStat中的各个位的意义进行描述,如图2.22所示。请求多事件请求信号量请求邮箱请求队列挂起请求互信斥号量请求事件标志组未用位:76543210图2.22OSTCBStat的低8位含义在这里,看到了我们熟悉的挂起,在从低到高的第4位,如果从0位开始算,是位3。我们还有如下的宏定义,如程序2.28所示。程序2.28关于任务状态的宏定义#defineOS_STAT_RDY0x00u/*未等待*/#defineOS_STAT_SEM0x01u/*等待信号量*/#defineOS_STAT_MBOX0x02u/*等待邮箱*/#defineOS_STAT_Q0x04u/*等待队列*/#defineOS_STAT_SUSPEND0x08u/*任务挂起*/28第2章任务管理#defineOS_STAT_MUTEX0x10u/*等待互斥信号量*/#defineOS_STAT_FLAG0x20u/*等待事件标志*/#defineOS_STAT_MULTI0x80u/*等待多事件*/#defineOS_STAT_PEND_ANY(OS_STAT_SEM|OS_STAT_MBOX|OS_STAT_Q|OS_STAT_MUTEX|OS_STAT_FLAG)因此程序2.27中(2)处OS_STAT_PEND_ANY是一个宏,这个宏的定义在程序2.28的最后,很明显,只要任务在等待任何一个事件发生,那么OS_STAT_PEND_ANY的值都不会是OS_STAT_RDY。因此(2)处条件判断语句的含义就是,如果任务在等待任何一个事件的发生(信号量、邮箱、队列、互斥信号量、标志),就执行下面的操作,将延迟时间减1,判断是否延迟结束等。这里需要提前给出的是,任务可能因为等待事件而处于阻塞态,但是阻塞态的任务的控

1 / 21
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功