任务管理
一、建立任务:OSTaskCreate、OSTaskCreateExt
1、参数:
void (*task)( void *pd):用指向函数的指针做函数参数。指向任务代码
*pdata:指向非强制性数据区域的指针,当任务优先运行时传递参数给任务(详)
*ptos:指向任务顶部的指针,如果配置常数OS_STK_GROWTH设置为1的话,堆栈则会
由高到底增长
定义两个变量 *psp、err,用于接收调用任务堆栈初始化、任务控制块初始化返回的值
OS_ARG_CHK_EN:是否允许大多数函数执行参数检查功能(是否为空,在指定范围内)
2、memest:
memest原型 (please type "man memset" in your shell)
void *memset(void *s, int c, size_t n);
memset:作用是在一段内存块中填充某个给定的值,它对较大的结构体或数组进行清零操作的一种最快方法。
memset为内存填充函数
void *memset(void *s,char ch,unsigned n)
memset将s的所有字节置于字节ch中.s数组的长度由n给出.
OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio):
对prio参检,关闭中断,检查这个优先级是否被其他任务占用,如果没有,放入一个非空指针,表示对这个优先级已经占用
开中断,调用函数OSTaskStkInit(task, pdata, ptos, 0)初始化(建立)任务堆栈,返回指向新任务堆栈的指针
调用函数OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0)从空闲的OS_TCB缓冲池中获得并初始化一个任务控制块,返回是否成功
在临界段内给任务数量加一
如果多任务开始,进行任务调度
如果初始化任务控制块有错,返回错误信息
INT8U OSTaskCreateExt
更加灵活但会增加一些额外的开销
二、堆栈检验,OSTaskStkChk
有时确定任务实际需要的堆栈空间大小事很必要的。这样就可以避免为任务分配过多的栈空间,从而减少过多的栈空间,从而减少应用代码所需的RAM(内存)数量
在堆栈检验时uc要求在任务建立时,堆栈中存储的必须是0
三、删除任务,OSTaskDel(prio)
如果参数检查的话,检查是否空闲任务,是否在允许范围内,然后进入临界状态,避免其他因素打断。
如果是删除任务本身的话(一个任务调用删除自己)获得自身任务的优先级,取出已建立的TCB的指针表((OSTCBPrioTbl[OS_LOWEST_PRIO + 1])如果不为空,每个任务都有个指向任务控制块的指针)。
首先,在任务就绪表中删除,如果认为处于互斥信号量、邮箱消息队列或信号量的等待表中,就从此表中删除(类似在就绪表中删除)。
OS版本大于等于251,能使用事件标志(如果在此任务在事件标志中等待),从等待列表中删除,删除任务后,将任务时钟节拍延迟数清0,确保自己重新开中断时,中断服务子程序ISR不会使该任务就绪。???
OSTaskDel()置任务的OSTCBStat标志为OS_STAT_RDY(OSTaskDel()并不试图使任务处于就绪态,只是阻止其它任务或者中断服务程序让该任务重新开始执行(通过调用OSTaskResume()).若不设置任务的OSTCBStat标志为OS_STAT_RDY,也可以清除OS_STAT_SUSPEND())。
至此,被删除的任务就不会被其它任务或者中断服务子程序置于就绪态//因为该任务已经从就绪任务表中被删了,为了在室删除任务目的,任务被置于休眠状态,正因为任务处于休眠状态,OSTaskDel()要防止任务调度程序在删除过程中切换到其它任务中去,因为当前任务如果正在被删除????,是不可能被再次调度。
多任务处理结点嵌套数如果小于255,嵌套数加一,重新开中断,以缩短响应时间,这样,OSTaskDel()就能够处理中断了,但是由于给OSLockNesting加了一,ISR执行完后,会返回到被中断了的任务,从而继续任务的删除工作????。
调用空函数OS_Dummy,保证中断开了(许多处理器执行完下一条指令才真正开中断),可以继续执行删除工作了,在OSTaskDel()重新关中断后,它通过锁定嵌套计数器减一,重新允许任务调度。????
调用自定义删除任务接口函数,可在这里删除或者释放自定义的TCB附加数据域
任务计数器减一,表明管理的任务减少了一个。
OSTaskDel()函数简单地指向被删除任务的TCB的指针置为NULL,就从优先级
表中把OS_TCB给删除了,我看着怎么是把这个优先级对应的指向这个任务控制块的指针置空呢?。
从以OSTCBList开头的OS_TCB双向链表中删除被删任务的TCB,ptcb->OSTCBNext->OSTCBPrev
被删任务的OS_TCB被退回到空闲的OS_TCB中,供其它任务使用
返回删除成功,否则返回失败
四、请求删除任务:OSTaskDelReq
有时候任务会占用一些内存缓冲区或信号量一类的资源。这是假如另一个任务试图删除该任务的时候,这些被占用的资源就会因为没有没释放而被丢失,这回导致存储器漏洞,所以我们要让任务使用完任务后先释放资源(我怎么没看到是怎么释放的呢???),再删除。发出删除任务请求的任务(RequestorTask(void *pdata))和打算删除的任务(TaskToBeDeleted(void *pdata))都需调用此函数
ptcb->OSTCBDelReq = OS_TASK_DEL_REQ;数值怎么能附给Boolean类型的呢???
如果删除的是自己,返回请求状态到调用者
关中断,得到指向该任务任务控制块的指针,如果此指针不为空(即任务存在),设置标志,表示即将删除,返回成功,否则返回失败
关中断
五、动态改变任务优先级OSTaskChangePrio (INT8U oldprio, INT8U newprio)
就是对这两个参数的操作
六、挂起任务OSTaskSuspend (INT8U prio)
挂起就是暂停的意思,挂起的任务只有通过调用OSTaskQuery (INT8U prio, OS_TCB *pdata)才能恢复。不能挂起空闲任务,但可以挂起当前任务。要保证要挂起的任务是存在的。挂起的方法是操作任务控制块,置位它的挂起位。如果任务在就绪表中,就要从表中去除,如果等待或者延时,就将延时清零,再置位挂起位。挂起后,只有在被挂起任务是调用本函数的任务本身,才需要任务调度。
七、恢复任务OSTaskResume (INT8U prio)
见下8
八、获得任务信息OSTaskQuery (INT8U prio, OS_TCB *pdata)
实际上,此函数获得的是指定任务的任务控制块OS_TCB中的内容的拷贝,详见下9
引:
uC/OS的任务要么是一个无限的循环,也可以在执行一次后被删除掉。要注意的是,这里所说的任务删除,并不是任务的代码被删除了,而是uC/OS不再去理它了,所以该任务代码不会再运行了。在uC/OS中,有一个代表任务优先级的值,这个值在每个任务中是不相同的。值越低,它代表任务的优先级越高,它在就绪表中排得越靠前。
1、建立任务:
任务的建立可以在多任务调度之前建立,也可以在运行其它任务的时候建立,但是,在多任务调度之前,必须要至少有已经建立了一个任务,否则系统被崩溃。还要注意的是任务不能在中断服务程序中建立。建立任务时,系统会首先检测用户指定的优先级是否合理(是不是超过最大值,是否与已创建任务重复等),如果合理,放置一个标记,说明这个优先级我已经占用了,其它任务不能抢我这个优先级了。再给这个任务建立一个任务堆栈,(堆栈可以由上往下减,也可以由下往上增,具体见参数如何设置),如果堆栈成功建立的话,就从空闲的任务控制块缓冲池中获得一块任务控制块OS_PCB,然后任务就成功了,这个时候,相关函数会返回信息,任务建立函数会检查返回信息,如果任务建立成功的话,会将任务计数器加一。如果失败,则返回失败信息,放弃此优先级,表明,别人任务可以来抢这个优先级了。
2、堆栈检验:
有时候,比如内存有限的情况下,确定任务实际需要的堆栈空间大小是比较有必要的,这样可以避免为任务分配过多的栈空间。注意:如果需要堆栈检验,那么在任务建立的时候,堆栈中存储必须是0。而且要检验堆栈的任务必须要存在,还要允许检验堆栈!这些长期保持都满足时,就可以检验了:当堆栈是从高内存地址向低地址存储的时候,我们就从低地址开始检验,直到发现存储值不为0的堆栈入口为止(因为堆栈是连续存储的)。而已用的堆栈就是堆栈大小减去空闲的堆栈。然后将所得到的信息保存。
应该要使自己的应用程序运行足够长的时间,并经历最坏的堆栈使用情况,这样才能得到正确的数目。一旦堆栈检测提供最坏情况的堆栈需求,就可以重新设置堆栈最终的大小了。为了系统升级和扩展,应该多分配10%到100%的堆栈空间。
3、删除任务:
首先要明白的是,任务删除了,并不是把代码给删了,而是使任务进入了休眠状态,不再理会它了。而且不允许在中断服务程序中删除任务,也不允许删除空闲任务,但可以删除统计任务和任务自己。在删除任务的时候,要首先保证要删除的任务存在,否则没有办法删除。再分几种情况讨论,如果要删除的任务在就绪表中,就要从就绪表中删除,如果在等待列表中,就要从等待列表中删除。如果在事件标志等待表中,也要从此表中删除。这个时候删除任务要保证其它任务或者ISR不会让该任务重新开始执行,这个时候,任务要释放或者删除自定义的TCB,还要将任务计数器减一,再把被删除任务的TCB的指针指向NULL,再把OS_TCB双向链表中的被删任务的TCB去除。退回到空闲TCB中,供其它任务使用。最后还要进行任务调度。
4、请求删除任务:
如果一任务正在占有一些内存缓冲区或者信号量一类资源,就时,另一任务想删除该任务,那么这么占有的资源就会因为没有释放而丢失了,导致了存储器有了漏洞,这样会导致系统崩溃。这些情况下,我们应该让这个任务用完资源释放后,再删除自己。
5、任务删除自己:
当被删除的任务释放完它所有的资源时,就在删除任务中将优先级设置为自己,这样就会删除自己了。要保证任务不能是空闲任务,且要保证请求删除任务的优先级是有效的。且此任务存在。
6、改变任务的优先级:
在改变前要检验,不能改变空闲任务的优先级,且要保证新旧优先级都要合法且不能已经被别的任务占有。如果要指定的新优先级空闲,则要保留这个优先级,防止过程中有别的任务来抢。这样,再释放旧的优先级,可以被其它任务用。再检查要改变优先级的任务是不是在就绪表中或者在等待信号量等,如果是,要将它从就绪表或者等待列表中移除,将任务的TCB保存,新的优先级也保存。完成这些步骤后,如果新优先级高于旧优先级,或者新优先级高于调用本函数的任务的优先级,任务调度将调用。
7、任务挂起:
不能挂起空闲任务,但可以挂起当前任务。要保证要挂起的任务是存在的。挂起的方法是操作任务控制块,置位它的挂起位。如果任务在就绪表中,就要从表中去除,如果等待或者延时,就将延时清零,再置位挂起位。挂起后,只有在被挂起任务是调用本函数的任务本身,才需要任务调度。
8、恢复任务:
首先要检验不是空闲任务,再清除挂起位,延时清零,只有保证这两点,任务才处于就绪状态。再调用任务调度程序。
9、获得任务信息:
应用程序可以调用此函数来获得自身或者其它应用程序的信息,注意,包括空闲任务!获得指定任务的任务控制块的拷贝。要十分小心地处理OS_TCB指向其它任务控制块的指针,不要试图改变这些指针!总是来说,它是一个有用的调试工具。