shivency

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1、任务什么时候会被删除?

  一开始,任务在操作系统中是以函数代码的形式存在的,在操作系统启动的时候被加载到内存中,并未运行。并且,最开始的时候就绪表和就绪组是空的,或者说里面的内容都是0.很明显,这时候任务在内存中睡眠,处于睡眠态。如果不调用任务创建函数对任务进行操作,该任务将永远处于睡眠态直到操作系统结束运行,被清除出内存。

  (好像没有正面回答这个问题……)

 

2、任务创建过程的回顾

  任务创建的过程:首先分配一个空闲的TCB给任务,然后对该TCB的各个域进行赋值,对任务的堆栈进行初始化,其中,任务的代码的地址被压入堆栈。这为以后任务的运行做了充分的准备。就绪表和就绪组做了适当的处理,根据任务的优先级进行了设置。就绪TCB链表也插入了该TCB

  而任务删除,便是任务创建的逆过程。

 

3、任务删除

  任务删除(func: OSTaskDel() ),便是将就绪表、就绪组进行逆向操作,就绪链表中的相关TCB应该被移除,转移到空闲TCB链表。和任务创建一样,也要进行一些检查,看任务是否符合被删除的条件。

  此外,任务删除还涉及一个请求删除(func: OSTaskDelReq() )的问题,因此任务删除看似简单,实际上是比较复杂的一个过程。

  所以,这一节将会提到两个函数。

 

我发现之前一个很不好的习惯,不同文章上流程图和代码的顺序不一样。以后统一先放流程图,再上代码好了。

 

4、任务删除函数:OSTaskDel()

 流程图:

 

挺长的,预示着这个函数并不算简单。

上代码:

 1 #if OS_TASK_DEL_EN > 0
 2 INT8U  OSTaskDel (INT8U prio)
 3 {
 4 #if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
 5     OS_FLAG_NODE *pnode;
 6 #endif
 7 
 8     OS_TCB       *ptcb;
 9     
10 #if OS_CRITICAL_METHOD == 3                             /* Allocate storage for CPU status register    */
11     OS_CPU_SR     cpu_sr = 0;
12 #endif
13 
14     if (OSIntNesting > 0) {                             /* See if trying to delete from ISR            */
15         return (OS_ERR_TASK_DEL_ISR);
16     }
17     if (prio == OS_TASK_IDLE_PRIO) {                    /* Not allowed to delete idle task             */
18         return (OS_ERR_TASK_DEL_IDLE);
19     }
20 #if OS_ARG_CHK_EN > 0
21     if (prio >= OS_LOWEST_PRIO) {                       /* Task priority valid ?                       */
22         if (prio != OS_PRIO_SELF) {
23             return (OS_ERR_PRIO_INVALID);
24         }
25     }
26 #endif

  line 7定义了一个任务控制块指针;

  之后便是一些参数的检查,注意line 22的OS_PRIO_SELF,为自身的优先级。当任务删除自身的时候,可使用

OSTaskDel (OS_RPIO_SELF)      //#define OS_PRIO_SELF 0XFFu

  之后便是包围在OS_ENTER_CRITICAL()与 OS_EXIT_CRITICAL()之间的内容,即开始访问全局变量。

 1     OS_ENTER_CRITICAL();
 2     if (prio == OS_PRIO_SELF) {                         /* See if requesting to delete self            */
 3         prio = OSTCBCur->OSTCBPrio;                     /* Set priority to delete to current           */
 4     }
 5     ptcb = OSTCBPrioTbl[prio];
 6     if (ptcb == (OS_TCB *)0) {                          /* Task to delete must exist                   */
 7         OS_EXIT_CRITICAL();
 8         return (OS_ERR_TASK_NOT_EXIST);
 9     }
10     if (ptcb == OS_TCB_RESERVED) {                      /* Must not be assigned to Mutex               */
11         OS_EXIT_CRITICAL();
12         return (OS_ERR_TASK_DEL);
13     }

  进入临界区,所以把全局变量中的OSTCBCur(当前任务)的优先级赋值给prio,把对应的地址传递给ptcb(已用红色标出)。

  至此参数已经检查完毕。之后便是根据各种标志,来选择性地对任务状态进行改变。

 1    OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX;
 2     if (OSRdyTbl[ptcb->OSTCBY] == 0) {                  /* Make task not ready                         */
 3         OSRdyGrp           &= ~ptcb->OSTCBBitY;
 4     }
 5     
 6 #if (OS_EVENT_EN)
 7     if (ptcb->OSTCBEventPtr != (OS_EVENT *)0) {
 8         OS_EventTaskRemove(ptcb, ptcb->OSTCBEventPtr);  /* Remove this task from any event   wait list */
 9     }
10 #if (OS_EVENT_MULTI_EN > 0)
11     if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) {   /* Remove this task from any events' wait lists*/
12         OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
13     }
14 #endif
15 #endif
16 
17 #if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
18     pnode = ptcb->OSTCBFlagNode;
19     if (pnode != (OS_FLAG_NODE *)0) {                   /* If task is waiting on event flag            */
20         OS_FlagUnlink(pnode);                           /* Remove from wait list                       */
21     }
22 #endif

  line 1~ line 4,是清除该任务的就绪标志;

  line 6~line 15,是清除任务等待事件的标志(get out of the line, I mean);

  line 17~line 22,是与事件标志组管理有关,未学到……

1     ptcb->OSTCBDly      = 0;                            /* Prevent OSTimeTick() from updating          */
2     ptcb->OSTCBStat     = OS_STAT_RDY;                  /* Prevent task from being resumed             */
3     ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
4     if (OSLockNesting < 255u) {                         /* Make sure we don't context switch           */
5         OSLockNesting++;
6     }
7     OS_EXIT_CRITICAL();                                 /* Enabling INT. ignores next instruc.         */

 

  line 2表示。该任务的state为OS_STAT_RDY, 并非表示该任务已经就绪了,而是去掉了诸如等待标志,实际上任务被删除了,将处于睡眠态。

  line4和line5,强行将调度器加上一次锁, 我不知道什么调度器,回过头来解释(1、为什么上锁;2、在哪里将该值减1)。

 1     OS_Dummy();                                         /* ... Dummy ensures that INTs will be         */
 2     OS_ENTER_CRITICAL();                                /* ... disabled HERE!                          */
 3     if (OSLockNesting > 0) {                            /* Remove context switch lock                  */
 4         OSLockNesting--;
 5     }
 6     OSTaskDelHook(ptcb);                                /* Call user defined hook                      */
 7     OSTaskCtr--;                                        /* One less task being managed                 */
 8     OSTCBPrioTbl[prio] = (OS_TCB *)0;                   /* Clear old priority entry                    */
 9     if (ptcb->OSTCBPrev == (OS_TCB *)0) {               /* Remove from TCB chain                       */
10         ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0;
11         OSTCBList                  = ptcb->OSTCBNext;
12     } else {
13         ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext;
14         ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev;
15     }
16     ptcb->OSTCBNext   = OSTCBFreeList;                  /* Return TCB to free TCB list                 */
17     OSTCBFreeList     = ptcb;
18 #if OS_TASK_NAME_SIZE > 1
19     ptcb->OSTCBTaskName[0] = '?';                       /* Unknown name                                */
20     ptcb->OSTCBTaskName[1] = OS_ASCII_NUL;
21 #endif
22     OS_EXIT_CRITICAL();

  OS_Dummy()只是一个空函数,换句话说,在喘了一口气之后,函数又关了中断。

  先把调度器减1?

  之后便是一系列的收官动作——OSTaskCtr减1,把这个任务从就绪表摘下插入空闲链表中。

  最后开中断。

1     if (OSRunning == OS_TRUE) {
2         OS_Sched();                                     /* Find new highest priority task              */
3     }
4     return (OS_ERR_NONE);

  此设计任务调度,回过头解释。

 

  至此,任务已删除完。由于任务删除的码很长,而执行过程中一直在访问全局变量,因此使系统不能响应中断——而作为一个RTOS,不能及时响应中断,那真是对不起它的招牌,于是,在整个函数的中间,又开了一次中断。

 

5、请求删除任务函数:OSTaskDelReq() 

上流程图:

 

 

 相对于第一个函数,OSTaskDelReq()看起来简单很多。

代码:
 1 #if OS_TASK_DEL_EN > 0
 2 INT8U  OSTaskDelReq (INT8U prio)
 3 {
 4     INT8U      stat;
 5     OS_TCB    *ptcb;
 6 #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
 7     OS_CPU_SR  cpu_sr = 0;
 8 #endif
 9 
10 
11 
12     if (prio == OS_TASK_IDLE_PRIO) {                            /* Not allowed to delete idle task     */
13         return (OS_ERR_TASK_DEL_IDLE);
14     }
15 #if OS_ARG_CHK_EN > 0
16     if (prio >= OS_LOWEST_PRIO) {                               /* Task priority valid ?               */
17         if (prio != OS_PRIO_SELF) {
18             return (OS_ERR_PRIO_INVALID);
19         }
20     }
21 #endif
22     if (prio == OS_PRIO_SELF) {                                 /* See if a task is requesting to ...  */
23         OS_ENTER_CRITICAL();                                    /* ... this task to delete itself      */
24         stat = OSTCBCur->OSTCBDelReq;                           /* Return request status to caller     */
25         OS_EXIT_CRITICAL();
26         return (stat);
27     }

  惯例,刚刚开始依然是参数检查。

  line 22中检查是否有任务删除自己。如果有,则返回任务控制块中OSTCBDelReq域中的参数,即是否有删除请求。

 1     OS_ENTER_CRITICAL();
 2     ptcb = OSTCBPrioTbl[prio];
 3     if (ptcb == (OS_TCB *)0) {                                  /* Task to delete must exist           */
 4         OS_EXIT_CRITICAL();
 5         return (OS_ERR_TASK_NOT_EXIST);                         /* Task must already be deleted        */
 6     }
 7     if (ptcb == OS_TCB_RESERVED) {                              /* Must NOT be assigned to a Mutex     */
 8         OS_EXIT_CRITICAL();
 9         return (OS_ERR_TASK_DEL);
10     }
11     ptcb->OSTCBDelReq = OS_ERR_TASK_DEL_REQ;                    /* Set flag indicating task to be DEL. */
12     OS_EXIT_CRITICAL();
13     return (OS_ERR_NONE);
14 }
15 #endif

  后半部分的代码根据参数不同,分别执行判断是否有请求参数标志给对方任务打上请求删除标志

 

6、OSTaskDel() 和 OSTaskDelReq()

  很潦草地分析完这两个代码,现在谈谈为什么要有两个删除函数,或者,为什么要有请求删除任务函数。

  

  有时候,任务会占用一些内存缓冲区或信号量一类的资源,这时假如另一个任务试图删除该任务,这些被占用的资源就会因为没有释放而丢失,造成内存泄露。

  就像在C中,强调,malloc动态分配内存后,一定要使用free释放一样。

 

  OSTaskDelReq名称虽然是请求,却是集请求与响应于一段代码内,该代码的功能是请求删除某任务和查看是否有任务要删除自己。

  所以,完整的删除流程是:两个任务一起合作,一个提出删除要求,另外一个在循环里面,首先执行删除要求判断,是否有其他任务要求删除它,是的话就马上释放资源,调

  用删除任务函数。提出删除要求的任务,就是简单的设置删除任务的一个域。被删除的任务就是检查那个域。

  两个函数合作删除。

 

7、链接

  最后放一个链接,作者自己把工程改了下,然后进行调试。我目前还没这水平:ucos任务删除



posted on 2013-07-15 12:54  shivency  阅读(606)  评论(0编辑  收藏  举报