0x01
摘要
ucos任务删除能够实现自身任务删除和删除其他任务,任务删除并不是直接将任务删除,而是将删除任务的信号设置到TCB中,任务在执行期间检测到删除的信号时便将自身的资源释放,否则会造成资源浪费和内存溢出。然后将其在TCB链表、事件链表中删除,将TCB块放回TCB空闲链表中。
0x02
引言
任务删除是为了在任务运行过程中能够实现资源的是释放,提高系统的运行效率。任务删除并不是直接删除,而是通过设置标志位实现任务的删除。
0x03
原理
首先我们先把源码附上,一行行进行解释
INT8U OSTaskDel (INT8U prio)
{
#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
OS_FLAG_NODE *pnode;
#endif
判断是否配置了标志位,定义变量
OS_TCB *ptcb;
设置TCB变量,用于本函数对TCB的操作。
#if OS_CRITICAL_METHOD == 3/* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
判断中断方式,具体作用在前面已经讲解过。
if (OSIntNesting > 0) {/* See if trying to delete from ISR*/
return (OS_ERR_TASK_DEL_ISR);
}
判断是否实在中断中,避免在中断中删除任务。
if (prio == OS_TASK_IDLE_PRIO) {/* Not allowed to delete idle task*/
return (OS_ERR_TASK_DEL_IDLE);
}
判断是否是空闲任务,因为空闲任务是系统必须有的,所以不能删除。
#if OS_ARG_CHK_EN > 0
if (prio >= OS_LOWEST_PRIO) {/* Task priority valid ? */
if (prio != OS_PRIO_SELF) {
return (OS_ERR_PRIO_INVALID);
}
}
#endif
参数检查,被删除任务的优先级不能超过最低优先级,但自身优先级除外,因为任务在运行后,会将自身优先级设为0xFF.
/*$PAGE*/分页的作用,如果将其复制到word中就会出现分页,应该是为了便于阅读,设定的分页符,对编程没有影响。
OS_ENTER_CRITICAL();
if (prio == OS_PRIO_SELF) {/* See if requesting to delete self*/
prio = OSTCBCur->OSTCBPrio; /* Set priority to delete to current*/
}
如果要是删除自身的话,需要将任务真正的优先级赋值给prio,便于对里面的参数进行操作。
ptcb = OSTCBPrioTbl[prio];
获取TCB的指针,OSTCBPrioTbl数组大家可以参考任务创建中的内容,用来存放TCB指针。
if (ptcb == (OS_TCB *)0) {/* Task to delete must exist*/
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST);
}
if (ptcb == OS_TCB_RESERVED) {/* Must not be assigned to Mutex*/
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_DEL);
}
以上是判断TCB的指针是否是空或者保留的。
OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX;
if (OSRdyTbl[ptcb->OSTCBY] == 0) { /* Make task not ready*/
OSRdyGrp &= ~ptcb->OSTCBBitY;
}
将任务从就绪表中剔除,具体参数的意思在前面都讲过。
#if (OS_EVENT_EN)
if (ptcb->OSTCBEventPtr != (OS_EVENT *)0) {
OS_EventTaskRemove(ptcb, ptcb->OSTCBEventPtr); /* Remove this task from any event wait list */
}
#if (OS_EVENT_MULTI_EN > 0)
if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { /* Remove this task from any events' wait lists*/
OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
}
将任务从事件列表中剔除,事件功能在后面给大家讲解具体原理。
#endif
#endif
#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
pnode = ptcb->OSTCBFlagNode;
if (pnode != (OS_FLAG_NODE *)0) {/* If task is waiting on event flag*/
OS_FlagUnlink(pnode); /* Remove from wait list*/
}
#endif
将任务从标志事件中剔除。
ptcb->OSTCBDly = 0; /* Prevent OSTimeTick() from updating*/
ptcb->OSTCBStat = OS_STAT_RDY; /* Prevent task from being resumed*/
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
将任务的延迟时间、状态、挂起状态都设定为正常状态,避免被相应的函数重新调用,进行再次调度。
if (OSLockNesting < 255u) { /* Make sure we don't context switch*/
OSLockNesting++;
}
OS_EXIT_CRITICAL();/* Enabling INT. ignores next instruc. */
OS_Dummy();/* ... Dummy ensures that INTs will be*/
这个函数具体不知道怎么用,备注显示是为了阻止中断函数。它的代码为空,不执行任何操作。
OS_ENTER_CRITICAL();/* ... disabled HERE! */
if (OSLockNesting > 0) {/* Remove context switch lock*/
OSLockNesting--;
}
OSTaskDelHook(ptcb); /* Call user defined hook*/
将任务从用户的钩子函数中删除,需要在用户开启了自定义的钩子函数功能才行。
OSTaskCtr--;/* One less task being managed*/
OSTCBPrioTbl[prio] = (OS_TCB *)0; /* Clear old priority entry*/
清空当前优先级在OSTCBPrioTbl中的指针,释放这个优先级。
if (ptcb->OSTCBPrev == (OS_TCB *)0) {/* Remove from TCB chain*/
ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0;
OSTCBList = ptcb->OSTCBNext;
} else {
ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext;
ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev;
}
判断是否是优先级链表中的第一个任务,然后根据结果将当前任务从优先级链表中剔除。链表元素的删除大家应该都了解,不了解的网上有很多资料,很容易理解的。
ptcb->OSTCBNext = OSTCBFreeList; /* Return TCB to free TCB list*/
OSTCBFreeList = ptcb;
将当前TCB加入到空闲TCB链表中,以便以后继续使用。
#if OS_TASK_NAME_SIZE > 1
ptcb->OSTCBTaskName[0] = '?'; /* Unknown name*/
ptcb->OSTCBTaskName[1] = OS_ASCII_NUL;
#endif
这里是清空任务的名字。
OS_EXIT_CRITICAL();
if (OSRunning == OS_TRUE) {
OS_Sched();/* Find new highest priority task*/
}
进行一次任务调度,到这里就完成了任务的删除。
return (OS_ERR_NONE);
}
0x04
结论
从任务删除函数可以看出,任务删除只要将任务从就绪表中剔除,不让调度函数进行调度。然后从事件列表、标志位事件列表中除去,然后把任务的任务剩余事件、状态、挂起状态统统设为正常状态,避免被相应的函数再次调度。然后把任务再从TCB列表删除,放入到空闲TCB列表中,就完成了任务的删除。其实就是不让任务再次进入到调度的行列中,任务不再被执行,就相当于其被删除了,尽管它的代码仍旧存在。
Change
你的努力
我的付出
如有任何疑问请后台回复
或添加作者Waiting_B_H
欢迎扫码一起分享经验
|