μC/OS-II的任务管理(下)

来源:本站
导读:目前正在解读《μC/OS-II的任务管理(下)》的相关信息,《μC/OS-II的任务管理(下)》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《μC/OS-II的任务管理(下)》的详细说明。
简介:μC/OS-II的任务管理

(2)

return(OS_PRIO_INVALID);

}

if(prio==OS_PRIO_SELF){(3)

OS_ENTER_CRITICAL();

stat=OSTCBCur->OSTCBDelReq;

OS_EXIT_CRITICAL();

return(stat);

}

else{

OS_ENTER_CRITICAL();

if((ptcb=OSTCBPrioTbl[prio])!=(OS_TCB*)0){(4)

ptcb->OSTCBDelReq=OS_TASK_DEL_REQ;(5)

err=OS_NO_ERR;

}else{

err=OS_TASK_NOT_EXIST;(6)

}

OS_EXIT_CRITICAL();

return(err);

}

}

4.6改变任务的优先级,OSTaskChangePrio()

在用户建立任务的时候会分配给任务一个优先级。在程序运行期间,用户可以通过调用OSTaskChangePrio()来改变任务的优先级。换句话说,就是μC/OS-Ⅱ允许用户动态的改变任务的优先级。

OSTaskChangePrio()的代码如程序清单L4.15所示。用户不能改变空闲任务的优先级[L4.15(1)],但用户可以改变调用本函数的任务或者其它任务的优先级。为了改变调用本函数的任务的优先级,用户可以指定该任务当前的优先级或OS_PRIO_SELF,

OSTaskChangePrio()会决定该任务的优先级。用户还必须指定任务的新(即想要的)优先级。因为μC/OS-Ⅱ不允许多个任务具有相同的优先级,所以OSTaskChangePrio()需要检验新优先级是否是合法的(即不存在具有新优先级的任务)[L4.15(2)]。如果新优先级是合法的,μC/OS-Ⅱ通过将某些东西储存到OSTCBPrioTbl[newprio]中保留这个优先级[L4.15(3)]。如此就使得OSTaskChangePrio()可以重新允许中断,因为此时其它任务已经不可能建立拥有该优先级的任务,也不能通过指定相同的新优先级来调用OSTaskChangePrio()。接下来OSTaskChangePrio()可以预先计算新优先级任务的OS_TCB中的某些值[L4.15(4)]。而这些值用来将任务放入就绪表或从该表中移除(参看3.04,就绪表)。

接着,OSTaskChangePrio()检验目前的任务是否想改变它的优先级[L4.15(5)]。然后,TaskChangePrio()检查想要改变优先级的任务是否存在[L4.15(6)]。很明显,如果要改变优先级的任务就是当前任务,这个测试就会成功。但是,如果OSTaskChangePrio()想要改变优先级的任务不存在,它必须将保留的新优先级放回到优先级表OSTCBPrioTbl[]中[L4.15(17)],并返回给调用者一个错误码。

现在, OSTaskChangePrio()可以通过插入NULL指针将指向当前任务OS_TCB的指针从优先级表中移除了[L4.15(7)]。这就使得当前任务的旧的优先级可以重新使用了。接着,我们检验一下OSTaskChangePrio()想要改变优先级的任务是否就绪[L4.15(8)]。如果该任务处于就绪状态,它必须在当前的优先级下从就绪表中移除[L4.15(9)],然后在新的优先级下插入到就绪表中[L4.15(10)]。这儿需要注意的是,OSTaskChangePrio()所用的是重新计算的值[L4.15(4)]将任务插入就绪表中的。

如果任务已经就绪,它可能会正在等待一个信号量、一封邮件或是一个消息队列。如果OSTCBEventPtr非空(不等于NULL)[L4.15(8)],OSTaskChangePrio()就会知道任务正在等待以上的某件事。如果任务在等待某一事件的发生,OSTaskChangePrio()必须将任务从事件控制块(参看6.00,事件控制块)的等待队列(在旧的优先级下)中移除。并在新的优先级下将事件插入到等待队列中[L4.15(12)]。 任务也有可能正在等待延时的期满(参看第五章-任务管理)或是被挂起(参看4.07,挂起任务,OSTaskSuspend())。在这些情况下,从L4.15(8)到L4.15(12)这几行可以略过。

接着,OSTaskChangePrio()将指向任务OS_TCB的指针存到OSTCBPrioTbl[]中[L4.15(13)]。 新的优先级被保存在OS_TCB中[L4.15(14)], 重新计算的值也被保存在OS_TCB中[L4.15(15)]。OSTaskChangePrio()完成了关键性的步骤后,在新的优先级高于旧的优先级或新的优先级高于调用本函数的任务的优先级情况下,任务调度程序就会被调用[L4.15(16)]。

程序清单 L4.15 OSTaskChangePrio().

INT8UOSTaskChangePrio(INT8Uoldprio,INT8Unewprio)

{

OS_TCB*ptcb;

OS_EVENT*pevent;

INT8Ux;

INT8Uy;

INT8Ubitx;

INT8Ubity;

if((oldprio>=OS_LOWEST_PRIO&&oldprio!=OS_PRIO_SELF)||(1)

newprio>=OS_LOWEST_PRIO){

return(OS_PRIO_INVALID);

}

OS_ENTER_CRITICAL();

if(OSTCBPrioTbl[newprio]!=(OS_TCB*)0){(2)

OS_EXIT_CRITICAL();

return(OS_PRIO_EXIST);

}else{

OSTCBPrioTbl[newprio]=(OS_TCB*)1;(3)

OS_EXIT_CRITICAL();

y=newprio>>3;(4)

bity=OSMapTbl[y];

x=newprio&0x07;

bitx=OSMapTbl[x];

OS_ENTER_CRITICAL();

if(oldprio==OS_PRIO_SELF){(5)

oldprio=OSTCBCur->OSTCBPrio;

}

if((ptcb=OSTCBPrioTbl[oldprio])!=(OS_TCB*)0){(6)

OSTCBPrioTbl[oldprio]=(OS_TCB*)0;(7)

if(OSRdyTbl[ptcb->OSTCBY]&ptcb->OSTCBBitX){(8)

if((OSRdyTbl[ptcb->OSTCBY]&=~ptcb->OSTCBBitX)==0){(9)

OSRdyGrp&=~ptcb->OSTCBBitY;

}

OSRdyGrp|=bity;(10)

OSRdyTbl[y]|=bitx;

}else{

if((pevent=ptcb->OSTCBEventPtr)!=(OS_EVENT*)0){(11)

if((pevent->OSEventTbl[ptcb->OSTCBY]&=

~ptcb->OSTCBBitX)==0){

pevent->OSEventGrp&=~ptcb->OSTCBBitY;

}

pevent->OSEventGrp|=bity;(12)

pevent->OSEventTbl[y]|=bitx;

}

}

OSTCBPrioTbl[newprio]=ptcb;(13)

ptcb->OSTCBPrio=newprio;(14)

ptcb->OSTCBY=y;(15)

ptcb->OSTCBX=x;

ptcb->OSTCBBitY=bity;

ptcb->OSTCBBitX=bitx;

OS_EXIT_CRITICAL();

OSSched();(16)

return(OS_NO_ERR);

}else{

OSTCBPrioTbl[newprio]=(OS_TCB*)0;(17)

OS_EXIT_CRITICAL();

return(OS_PRIO_ERR);

}

}

}

4.7 挂起任务,OSTaskSuspend()

有时候将任务挂起是很有用的。挂起任务可通过调用OSTaskSuspend()函数来完成。被挂起的任务只能通过调用OSTaskResume()函数来恢复。任务挂起是一个附加功能。也就是说,如果任务在被挂起的同时也在等待延时的期满,那么,挂起操作需要被取消,而任务继续等待延时期满,并转入就绪状态。任务可以挂起自己或者其它任务。

OSTaskSuspend()函数的代码如程序清单L4.16所示。通常OSTaskSuspend()需要检验临界条件。首先,OSTaskSuspend()要确保用户的应用程序不是在挂起空闲任务[L4.16(1)],接着确认用户指定优先级是有效的[L4.16(2)]。记住最大的有效的优先级数(即最低的优先级)是OS_LOWEST_PRIO。注意,用户可以挂起统计任务(statistic) 。可能用户已经注意到了,第一个测试[L4.16(1)]在[L4.16(2)]中被重复了。笔者这样做是为了能与μC/OS兼容。

第一个测试能够被移除并可以节省一点程序处理的时间,但是,这样做的意义不大,所以笔者决定留下它。

接着, OSTaskSuspend()检验用户是否通过指定 OS_PRIO_SELF来挂起调用本函数的任务本身[L4.16(3)]。用户也可以通过指定优先级来挂起调用本函数的任务[L4.16(4)]。在这两种情况下,任务调度程序都需要被调用。这就是笔者为什么要定义局部变量self的原因,该变量在适当的情况下会被测试。如果用户没有挂起调用本函数的任务,OSTaskSuspend()就没有必要运行任务调度程序,因为正在挂起的是较低优先级的任务。

然后,OSTaskSuspend()检验要挂起的任务是否存在[L4.16(5)]。如果该任务存在的话,它就会从就绪表中被移除[L4.16(6)]。注意要被挂起的任务有可能没有在就绪表中,因为它有可能在等待事件的发生或延时的期满。在这种情况下,要被挂起的任务在OSRdyTbl[]中对应的位已被清除了(即为0)。再次清除该位,要比先检验该位是否被清除了再在它没被清除时清除它快得多,所以笔者没有检验该位而直接清除它。现在,OSTaskSuspend()就可以在任务的OS_TCB中设置OS_STAT_SUSPEND标志了,以表明任务正在被挂起[L4.16(7)]。最后,OSTaskSuspend()只有在被挂起的任务是调用本函数的任务本身的情况下才调用任务调度程序[L4.16(8)]。

程序清单 L4.16 OSTaskSuspend().

INT8UOSTaskSuspend(INT8Uprio)

{

BOOLEANself;

OS_TCB*ptcb;

if(prio==OS_IDLE_PRIO){(1)

return(OS_TASK_SUSPEND_IDLE);

}

if(prio>=OS_LOWEST_PRIO&&prio!=OS_PRIO_SELF){

(2)

return(OS_PRIO_INVALID);

}

OS_ENTER_CRITICAL();

if(prio==OS_PRIO_SELF){(3)

prio=OSTCBCur->OSTCBPrio;

self=TRUE;

}elseif(prio==OSTCBCur->OSTCBPrio){(4)

self=TRUE;

}else{

self=FALSE;

}

if((ptcb=OSTCBPrioTbl[prio])==(OS_TCB*)0){(5)

OS_EXIT_CRITICAL();

return(OS_TASK_SUSPEND_PRIO);

}else{

if((OSRdyTbl[ptcb->OSTCBY]&=~ptcb->OSTCBBitX)==0){(6)

OSRdyGrp&=~ptcb->OSTCBBitY;

}

ptcb->OSTCBStat|=OS_STAT_SUSPEND;(7)

OS_EXIT_CRITICAL();

if(self==TRUE){(8)

OSSched();

}

return(OS_NO_ERR);

}

}

4.8 恢复任务,OSTaskResume()

在上一节中曾提到过,被挂起的任务只有通过调用OSTaskResume()才能恢复。OSTaskResume()函数的代码如程序清单L4.17所示。 因为OSTaskSuspend()不能挂起空闲任务,所以必须得确认用户的应用程序不是在恢复空闲任务[L4.17(1)]。注意,这个测试也可以确保用户不是在恢复优先级为OS_PRIO_SELF的任务(OS_PRIO_SELF被定义为0xFF,它总是比OS_LOWEST_PRIO大)。

要恢复的任务必须是存在的,因为用户要需要操作它的任务控制块OS_TCB[L4.17(2)],并且该任务必须是被挂起的[L4.17(3)]。OSTaskResume()是通过清除OSTCBStat域中的OS_STAT_SUSPEND位来取消挂起的[L4.17(4)]。要使任务处于就绪状态,OS_TCBDly域必须为0[L4.17(5)],这是因为在OSTCBStat中没有任何标志表明任务正在等待延时的期满。只有当以上两个条件都满足的时候,任务才处于就绪状态[L4.17(6)]。最后,任务调度程序会检查被恢复的任务拥有的优先级是否比调用本函数的任务的优先级高[L4.17(7)]。

程序清单 L4.17 OSTaskResume().

INT8UOSTaskResume(INT8Uprio)

{

OS_TCB*ptcb;

If(prio>=OS_LOWEST_PRIO){(1)

return(OS_PRIO_INVALID);

}

OS_ENTER_CRITICAL();

If((ptcb=OSTCBPrioTbl[prio])==(OS_TCB*)0){(2)

OS_EXIT_CRITICAL();

return(OS_TASK_RESUME_PRIO);

}else{

if(ptcb->OSTCBStat&OS_STAT_SUSPEND){(3)

if(((ptcb->OSTCBStat&=~OS_STAT_SUSPEND)==OS_STAT_RDY)&&(4)

(ptcb->OSTCBDly==0)){(5)

OSRdyGrp|=ptcb->OSTCBBitY;(6)

OSRdyTbl[ptcb->OSTCBY]|=ptcb->OSTCBBitX;

OS_EXIT_CRITICAL();

OSSched();(7)

}else{

OS_EXIT_CRITICAL();

}

return(OS_NO_ERR);

}else{

OS_EXIT_CRITICAL();

return(OS_TASK_NOT_SUSPENDED);

}

}

}

4.9 获得有关任务的信息,OSTaskQuery()

用户的应用程序可以通过调用OSTaskQuery()来获得自身或其它应用任务的信息。实际上,OSTaskQuery()获得的是对应任务的 OS_TCB中内容的拷贝。用户能访问的OS_TCB的数据域的多少决定于用户的应用程序的配置(参看OS_CFG.H)。由于μC/OS-Ⅱ是可裁剪的,它只包括那些用户的应用程序所要求的属性和功能。

要调用OSTaskQuery(),如程序清单L4.18中所示的那样,用户的应用程序必须要为OS_TCB分配存储空间。这个OS_TCB与μC/OS-Ⅱ分配的OS_TCB是完全不同的数据空间。在调用了OSTaskQuery()后,这个OS_TCB包含了对应任务的OS_TCB的副本。用户必须十分小心地处理OS_TCB中指向其它OS_TCB的指针(即OSTCBNext与OSTCBPrev);用户不要试图去改变这些指针! 一般来说, 本函数只用来了解任务正在干什么——本函数是有用的调试工具。

程序清单 L4.18 得到任务的信息

OS_TCBMyTaskData;

voidMyTask(void*pdata)

{

pdata=pdata;

for(;;){

/* 用户代码 */

err=OSTaskQuery(10,&MyTaskData);

/*Examineerrorcode..*/

/* 用户代码 */

}

}

OSTaskQuery()的代码如程序清单L4.19所示。注意,笔者允许用户查询所有的任务,包括空闲任务[L4.19(1)]。 用户尤其需要注意的是不要改变OSTCBNext与OSTCBPrev的指向。

通常,OSTaskQuery()需要检验用户是否想知道当前任务的有关信息[L4.19(2)]以及该任务是否已经建立了[L4.19(3)]。 所有的域是通过赋值语句一次性复制的而不是一个域一个域地复制的[L4.19(4)]。这样复制会比较快一点,因为编译器大多都能够产生内存拷贝指令。

程序清单 L4.19 OSTaskQuery().

INT8UOSTaskQuery(INT8Uprio,OS_TCB*pdata)

{

OS_TCB*ptcb;

if(prio>OS_LOWEST_PRIO&&prio!=OS_PRIO_SELF){(1)

return(OS_PRIO_INVALID);

}

OS_ENTER_CRITICAL();

if(prio==OS_PRIO_SELF){(2)

prio=OSTCBCur->OSTCBPrio;

}

if((ptcb=OSTCBPrioTbl[prio])==(OS_TCB*)0){(3)

OS_EXIT_CRITICAL();

return(OS_PRIO_ERR);

}

*pdata=*ptcb;(4)

OS_EXIT_CRITICAL();

return(OS_NO_ERR);

}

提醒:《μC/OS-II的任务管理(下)》最后刷新时间 2024-03-14 01:07:07,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《μC/OS-II的任务管理(下)》该内容的真实性请自行鉴别。