UC/OS II 任务管理(5)之任务删除、阻塞和恢复

来源:互联网 发布:无用神力兄弟会 知乎 编辑:程序博客网 时间:2024/06/02 11:02
任务的删除
     任务的删除就是任务创建的逆过程,需要将就绪组,就绪表、就绪组中将该任务优先级的标志清零。将对应的TCB的任务控制块从就绪链表中移除,转移到空闲链表。
        和任务创建一样,任务的删除也需要进行一些检查,看任务是否符合被删除的条件。具体的删除过程看任务的删除函数。
1:任务删除函数INT8U  OSTaskDel (INT8U prio) 
其函数代码如下,其参数很简单,就是只需要传递需要删除任务的优先级即可。
#if OS_TASK_DEL_EN > 0u   //任务删除功能需要配置OS_TASK_DEL_EN才能实现
INT8U  OSTaskDel (INT8U prio)  
{
#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
    OS_FLAG_NODE *pnode;     
#endif
    OS_TCB       *ptcb;
#if OS_CRITICAL_METHOD == 3u                            /* Allocate storage for CPU status register    */
    OS_CPU_SR     cpu_sr = 0u;
#endif



    if (OSIntNesting > 0u) {                            //若是在中断程序中执行删除任务会不成功
        return (OS_ERR_TASK_DEL_ISR);
    }
    if (prio == OS_TASK_IDLE_PRIO) {                    //空闲任务肯定是不允许被删除的
        return (OS_ERR_TASK_DEL_IDLE);
    }
#if OS_ARG_CHK_EN > 0u
    if (prio >= OS_LOWEST_PRIO) {                       //检查请求删除任务的优先级是否符合要求
        if (prio != OS_PRIO_SELF) {
            return (OS_ERR_PRIO_INVALID);
        }
    }
#endif
以上都是进行一些必要的参数检查

/*$PAGE*/
    OS_ENTER_CRITICAL();     
    if (prio == OS_PRIO_SELF) {                         //任务请求自己删除
        prio = OSTCBCur->OSTCBPrio;                     /* Set priority to delete to current           */
    }
    ptcb = OSTCBPrioTbl[prio];                    
    if (ptcb == (OS_TCB *)0) {                          //对应任务控制块指针为空的时候,说明该任务不存在
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_NOT_EXIST);
    }
    if (ptcb == OS_TCB_RESERVED) {                      //ptcb 为OS_TCB_RESERVED时候,该任务还创建中,删除是会不成功的
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_DEL);
    }

    OSRdyTbl[ptcb->OSTCBY] &= (OS_PRIO)~ptcb->OSTCBBitX;   //将就绪组中就绪组中相应的位清零
    if (OSRdyTbl[ptcb->OSTCBY] == 0u) {                 //若是删除的优先级所在的整个组中都没有了就绪任务,则将就绪表中对应的位清零。具体的分析在就绪列表和就绪数组中有说明
        OSRdyGrp           &= (OS_PRIO)~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 > 0u)
    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 > 0u) && (OS_MAX_FLAGS > 0u)//事件标志
    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      = 0u;                           /* Prevent OSTimeTick() from updating          */
    ptcb->OSTCBStat     = OS_STAT_RDY;                  /* Prevent task from being resumed             */
    ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
    if (OSLockNesting < 255u) {                         //在这期间,系统不能进行任务的上下文切换。
        OSLockNesting++;
    }
    OS_EXIT_CRITICAL();                                 /* Enabling INT. ignores next instruc.         */
    OS_Dummy();                                         /* ... Dummy ensures that INTs will/
    OS_ENTER_CRITICAL();                                /* ... disabled HERE!                          */
    if (OSLockNesting > 0u) {                           /* Remove context switch lock                  */
        OSLockNesting--;
    }
    OSTaskDelHook(ptcb);                                /* Call user defined hook                      */
    OSTaskCtr--;                                        //系统中创建好的任务数减1
    OSTCBPrioTbl[prio] = (OS_TCB *)0;                   //对应的任务控制块指针清零
    if (ptcb->OSTCBPrev == (OS_TCB *)0) {               //从就绪链表中移除
        ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0;
        OSTCBList                  = ptcb->OSTCBNext;
    } else {
        ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext;
        ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev;
    }
    ptcb->OSTCBNext     = OSTCBFreeList;                //将该任务控制块移到任务控制块空闲链表中
    OSTCBFreeList       = ptcb;
#if OS_TASK_NAME_EN > 0u
    ptcb->OSTCBTaskName = (INT8U *)(void *)"?";
#endif
    OS_EXIT_CRITICAL();
    if (OSRunning == OS_TRUE) {
        OS_Sched();                                     //重新调度程序
    }
    return (OS_ERR_NONE);
}
#endif

1.2:任务删除请求函数INT8U  OSTaskDelReq (os_task.c)
删除任务可以直接使用OSTaskDel简单粗暴的对任务进行删除,但是这样的话,可能会使任务之前占有的资源不能够得到释放,系统会产生内存泄漏等问题。
所以在进行任务删除的时候,我们可以先通知任务,告诉该任务,需要删除你,请任务自己删除自己。可以让任务在被删除之前能够释放自己的资源,例如队列、缓冲区、信号量。邮箱、队列等。
虽然名为请求,但是该函数集请求响应于一体。该代码的功能是请求删除某任务和查看是否有任务要删除自己。

其代码比较简单,前面一直都是参数检测。后面根据参数不同,分别判断是任务自己请求删除还是其他任务要求删除该任务,则分别执行判断是否有请求参数标志和给对方任务打上请求任务删除标志。
if (prio == OS_PRIO_SELF) {                                 /* See if a task is requesting to ...  */
        OS_ENTER_CRITICAL();                                    /* ... this task to delete itself      */
        stat = OSTCBCur->OSTCBDelReq;                           /* Return request status to caller     */
        OS_EXIT_CRITICAL();
        return (stat);
    }//若是自己请求删除自己,返回本任务控制块OSTCBDelReq
否则的话,就是给请求删除任务的控制块的OSTCBDelReq 成员打上OS_ERR_TASK_DEL_REQ 的标签。ptcb->OSTCBDelReq = OS_ERR_TASK_DEL_REQ;

1.3:任务的阻塞函数OSTaskSuspend
任务阻塞函数的功能就是将任务的状态从就绪态转为阻塞态,直至调用OSTaskResume将其唤醒转为就绪态,或者是该任务被删除进入睡眠状态。
具体前面的代码都是一些参数检查,跟任务删除,创建之类的函数差不多。其核心代码为下面五行,就是将就绪组表和就绪数组中任务的相应标志取消:
y            = ptcb->OSTCBY;
    OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;                  
    if (OSRdyTbl[y] == 0u) {
        OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
    }
    ptcb->OSTCBStat |= OS_STAT_SUSPEND;                         

1.4:任务恢复函数 OSTaskResume
任务恢复函数就是将阻塞状态的任务恢复为就绪状态
具体前面的代码都是一些参数检查,跟任务删除,创建、阻塞函数之类的函数差不多。其核心代码为下面:
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) != OS_STAT_RDY) { //判断是否任务在阻塞状态
        ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_SUSPEND;    //将任务控制块的状态成员OSTCBStat的阻塞态取消
        if (ptcb->OSTCBStat == OS_STAT_RDY) {                 //查看任务状态是否为就绪态
            if (ptcb->OSTCBDly == 0u) {
                OSRdyGrp               |= ptcb->OSTCBBitY;    //将就绪组和就绪数组中的相应的位置为1
                OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                OS_EXIT_CRITICAL();
                if (OSRunning == OS_TRUE) {
                    OS_Sched();                            
                }
0 0
原创粉丝点击