shivency

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

1、什么是任务的挂起

  任务在创建后将从睡眠态转换到就绪态,就绪的任务可以通过调用函数(OSTaskSuspend),剥夺起CPU的使用权,而使其暂时中止运行,转到阻塞状态。这个过程叫做挂起任务。

  image:排队排的好好的(这个情景不对- -),突然天降大手将你抓起,高高挂起【有一点不恰当,任务是可以自己挂起自己的】。

 

2、为什么要任务挂起

  一个任务如果无事可做,且优先级又高,长期占有CPU,使其他任务得不到运行而“饿死”。这时我们便需要采取“挂起”的策略;当然解决这个问题的方法不止一种,还有任务延时等策略,将会在后面学习到,这里先挖个坑。

 

3、什么是任务的恢复

  被挂起的任务不能运行,直到其他任务以该任务的优先级作为参数调用函数(OSTaskResume)恢复,才能使之重新设置为就绪态。

  image:当你知错的时候(必要时),大手根据你被挂起的位置(优先级),将你重新放回等待队列【没有自己恢复自己一说】。

 

4、tip:阻塞态和挂起态是两种不同的状态(继续挖坑)。

 

5、任务阻塞函数:OSTaskSuspend

流程图

 

 

 

源码:

 1 #if OS_TASK_SUSPEND_EN > 0
 2 INT8U  OSTaskSuspend (INT8U prio)
 3 {
 4     BOOLEAN    self;
 5     OS_TCB    *ptcb;
 6     INT8U      y;
 7 #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
 8     OS_CPU_SR  cpu_sr = 0;
 9 #endif
10 
11 
12 
13 #if OS_ARG_CHK_EN > 0
14     if (prio == OS_TASK_IDLE_PRIO) {                            /* Not allowed to suspend idle task    */
15         return (OS_ERR_TASK_SUSPEND_IDLE);        //不允许阻止空闲任务
16     }
17     if (prio >= OS_LOWEST_PRIO) {                               /* Task priority valid ?               */
18         if (prio != OS_PRIO_SELF) {
19             return (OS_ERR_PRIO_INVALID);        //非法的优先级
20         }
21     }
22 #endif

这段代码对参数的检查,其间有两个宏定义,之后便关中断,进入全局定义。

 1     OS_ENTER_CRITICAL();
 2     if (prio == OS_PRIO_SELF) {                                 /* See if suspend SELF                 */
 3         prio = OSTCBCur->OSTCBPrio;
 4         self = OS_TRUE;
 5     } else if (prio == OSTCBCur->OSTCBPrio) {                   /* See if suspending self              */
 6         self = OS_TRUE;
 7     } else {
 8         self = OS_FALSE;                                        /* No suspending another task          */
 9     }
10     ptcb = OSTCBPrioTbl[prio];
11     if (ptcb == (OS_TCB *)0) {                                  /* Task to suspend must exist          */
12         OS_EXIT_CRITICAL();
13         return (OS_ERR_TASK_SUSPEND_PRIO);        //要挂起的任务不存在
14     }
15     if (ptcb == OS_TCB_RESERVED) {                              /* See if assigned to Mutex            */
16         OS_EXIT_CRITICAL();
17         return (OS_ERR_TASK_NOT_EXIST);          //要挂起使用互斥信号量的任务
18     }

line 1~ line 9:如果优先级是OS_PRIO_SELF,取得自己真正的优先级,注意这里对变量self的赋值

line 11~ line 18:好像依然是参数检查,因为这里的参数检查涉及到全局变量,所以得在关中断后。

 1     y  = ptcb->OSTCBY;
 2     OSRdyTbl[y] &= ~ptcb->OSTCBBitX;                            /* Make task not ready                 */
 3     if (OSRdyTbl[y] == 0) {
 4         OSRdyGrp &= ~ptcb->OSTCBBitY;
 5     }
 6     ptcb->OSTCBStat |= OS_STAT_SUSPEND;                         /* Status of task is 'SUSPENDED'       */
 7     OS_EXIT_CRITICAL();
 8     if (self == OS_TRUE) {                                      /* Context switch only if SELF         */
 9         OS_Sched();                                             /* Find new highest priority task      */
10     }
11     return (OS_ERR_NONE);        //成功挂起一个任务
12 }
13 #endif

line 1~ line 5,很有意思,是取消就绪表和就绪组中的就绪标志。

line 6的注释,说明任务是在这句被挂起了(不涉及具体数值的分析)。【注红是为了表示这个才是整个函数的核心】

line 7~ line 8,如果任务是挂起自己(self在这里用到),这时才失去CPU的使用权。

 

6、任务恢复函数:OSTaskResume

流程图

源码:

 1 #if OS_TASK_SUSPEND_EN > 0
 2 INT8U  OSTaskResume (INT8U prio)
 3 {
 4     OS_TCB    *ptcb;
 5 #if OS_CRITICAL_METHOD == 3                                   /* Storage for CPU status register       */
 6     OS_CPU_SR  cpu_sr = 0;
 7 #endif
 8 
 9 #if OS_ARG_CHK_EN > 0
10     if (prio >= OS_LOWEST_PRIO) {                             /* Make sure task priority is valid      */
11         return (OS_ERR_PRIO_INVALID);    //非法优先级
12     }
13 #endif

惯例,参数检查。

 1     OS_ENTER_CRITICAL();
 2     ptcb = OSTCBPrioTbl[prio];
 3     if (ptcb == (OS_TCB *)0) {                                /* Task to suspend must exist            */
 4         OS_EXIT_CRITICAL();
 5         return (OS_ERR_TASK_RESUME_PRIO);  //要恢复的任务不存在
 6     }
 7     if (ptcb == OS_TCB_RESERVED) {                            /* See if assigned to Mutex              */
 8         OS_EXIT_CRITICAL();
 9         return (OS_ERR_TASK_NOT_EXIST);    //要挂起使用互斥信号量的任务
10 }

涉及全局变量的参数检查。

 1     if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) != OS_STAT_RDY) { /* Task must be suspended                */
 2         ptcb->OSTCBStat &= ~(INT8U)OS_STAT_SUSPEND;           /* Remove suspension                     */
 3         if (ptcb->OSTCBStat == OS_STAT_RDY) {                 /* See if task is now ready              */
 4             if (ptcb->OSTCBDly == 0) {
 5                 OSRdyGrp               |= ptcb->OSTCBBitY;    /* Yes, Make task ready to run           */
 6                 OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
 7                 OS_EXIT_CRITICAL();
 8                 if (OSRunning == OS_TRUE) {
 9                     OS_Sched();                               /* Find new highest priority task        */
10                 }
11             } else {
12                 OS_EXIT_CRITICAL();
13             }
14         } else {                                              /* Must be pending on event              */
15             OS_EXIT_CRITICAL();
16         }
17         return (OS_ERR_NONE);
18     }
19     OS_EXIT_CRITICAL();
20     return (OS_ERR_TASK_NOT_SUSPENDED);
21 }
22 #endif

阻塞和恢复是一对逆过程,在阻塞中标志OSTCBStat以示任务被挂起,当然在恢复函数中要对OSTCBStat操作,使其就绪。

line 1判断该任务是否为挂起状态;

line 2移除了挂起的标志;

line 3判断OSTCBStat是否为0,因为任务阻塞的原因不一样。假如任务因为等待信号量而被阻塞,那么即使清除了挂起标志,OSTCBStat还不为0。即任务还在等待诸如信号量、邮箱、队列等事件的发生,因此仍不能就绪。

line 4判断任务是否还在等待延时,如果是,也不能进入就绪态。

 

7、链接

  很巧,找资料时又看到那位大神自己玩任务的挂起和恢复,继续mark:ucos任务的挂起和恢复。

 

8、任务的调度

  自上次任务的删除开始,我们便接触到了任务调度这个概念。这次两个函数里都有涉及到一个叫做OS_Sched()这个函数。

  下一节便是学习任务调度。

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