需要删除自己的任务(任务A)的代码如程序清单 L4.13所示。在OS_TAB中存有一个标志,任务通过查询这个标志的值来确认自己是否需要被删除。这个标志的值是通过调用OSTaskDelReq (OS_PRIO_SELF)而得到的。当OSTaskDelReq()返回给调用者OS_TASK_DEL_REQ[L4.13(1)]时,则表明已经 有另外的任务请求该任务被删除了。在这种情况下,被删除的任务会释放它所拥有的所用资源[L4.13(2)],并且调用OSTaskDel (OS_PRIO_SELF)来删除自己[L4.13(3)]。前面曾提到过,任务的代码没有被真正的删除,而只是µC/OS-Ⅱ不再理会该任务代码,换 句话说,就是任务的代码不会再运行了。但是,用户可以通过调用OSTaskCreate()或OSTaskCreateExt()函数重新建立该任务。
OSTaskDelReq ()的代码如程序清单 L4.14所示。通常OSTaskDelReq()需要检查临界条件。首先,如果正在删除的任务是空闲任务,OSTaskDelReq()会报错并返回 [L4.14(1)]。接着,它要保证调用者请求删除的任务的优先级是有效的[L4.14(2)]。如果调用者就是被删除任务本身,存储在OS_TCB中 的标志将会作为返回值[L4.14(3)]。如果用户用优先级而不是OS_PRIO_SELF指定任务,并且任务是存在的[L4.14(4)], OSTaskDelReq()就会设置任务的内部标志[L4.14(5)]。如果任务不存在,OSTaskDelReq()则会返回 OS_TASK_NOT_EXIST,表明任务可能已经删除自己了[L4.14(6)]。 程序清单 L 4.14 OSTaskDelReq().
INT8U OSTaskDelReq (INT8U prio)
{
BOOLEAN stat;
INT8U err;
OS_TCB *ptcb;
if (prio == OS_IDLE_PRIO) { (1)
return (OS_TASK_DEL_IDLE);
}
if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { (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);
}
}
改变任务的优先级,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)]。然后,OSTaskChangePrio()检查 想要改变优先级的任务是否存在[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()完成了关键 性的步骤后,在新的优先级高于旧的优先级或新的优先级高于调用本函数的任务的优先级情况下,任务调度程序就会被调用 |