任务调度 (好资料)

  ucos的任务调度思想是:“近似的让每时每刻让优先级最高的就绪任务处于运行状态”。在具体做法上,他在系统或用户任务调用系统函数及执行中断服务程序结束时来调用调度器,以确定应该运行的任务并运行它。

        1,调度器的主要工作

      在多任务系统中,令CPU中止当前正在运行的任务转而去运行另一个任务的工作叫做任务切换,而按某种规则进行任务切换的工作叫做任务调度。           这番话有火车站的味道,列车的调度

      在ucos中,任务调度由任务调度器来完成。任务调度器的主要工作有两项:1,从任务就绪表中查找具有最高优先级别的就绪任务2,实现任务的切换。ucos中有两种调度器:一种是任务级的调度器,另一种是中断级的调度器。任务级的调度器主要有OSSched()来实现。而中断级的调度器由OSIntExt()来实现。

    2获得待运行就绪任务控制块的指针

    由于操作系统是通过任务的控制块TCB来管理任务的,因此调度器真正实施任务切换之前的主要工作就是要获得待运行任务的任务控制块指针和当前任务的任务控制块指针。

     由于被中止任务的任务控制块指针就存放在全局变量OSTCBCur中,所以调度器这部分的主要工作是要获得待运行任务的任务控制块指针

  void OSSched(void)
{
        #if OS_CRITICAL_METHOD == 3
         OS_CPU_SR cup_sr;
          #endif

        INT8U y;
 
        OS_ENTER_CRITICAL();


        if((OSLockNesting | OSIntNesting) == 0)
      {
              y = OSUnMapTbl[OSRdyGrp];
              OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); //获得最高优先级任务
              if(OSPrioHighRdy != OSPrioCur)
              {
                    OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];  //统计任务切换次数的计数器加1
                     OSCtxSwCtr++;
                     OS_TASK_SW();

               }

          }


           OS_EXIT_CRITICAL();
}

ucos允许应用程序通过调用函数OSSchedLock()和OSSchedUnlock()给调度器上锁和解锁。为了记录调度器被锁和解锁的情况,ucos定义了一个变量OSLockNesting;调度器每被上锁一次,变量OSLockNesting就加1;反之,调度器每被解锁一次,变量OSLockNesting就减1.因此可以通过访问变量OSLockNesting来了解调度器上锁的嵌套次数

     调度器OSSched()再确认未被上锁并且不是中断服务程序调用调度器的情况下,首先从任务就绪表中查得的最高优先级别就绪任务的优先级别OSPrioHighRdy;然后在确认了这个就绪任务不是当前正在运行的任务(OSPrioCur是存放正在运行任务的优先级别的变量)的条件下,用OSPrioHighRdy作为下标去访问数组OSTCBPrioTbl[],把数组元素OSTCBPrioTbl[OSPrioHighRdy]的值(及待运行就绪任务的任务控制块指针)赋给指针变量OSTCBHighRdy。于是下面就可以依据OSTCBHighRdy和OSTCBCur这两个分别指向待运行任务控制块和当前任务控制块的指针在宏OS_TASK_SW()中实施切换

任务调度 (好资料)_第1张图片
3任务切换宏OS_TASK_SW()    讨论了任务堆栈对任务的作用
   其实任务切换是靠OSCtxSW()来完成的
    简单的说,任务切换就是中止正在运行的任务(当前任务),转而去运行另外一个任务的操作。当然,这个任务应该是就绪任务中优先级别最高的那个任务
   为了了解调度器是如何进行任务切换的,先讨论一下一个被中止运行的任务(可可能因为中断或者调用),将来又要“无缝”地恢复运行应该满足什么条件。
    为了讨论的方便,如果把任务被中止运行时的位置叫做断点,把当时存放在CPU的PC,PSW和通用寄存器等各寄存器中的数据叫做断点数据,那么当任务恢复运行时,必须在断点处以断点数据作为初始数据接着运行才能实现“无缝”的接续运行。因此要实现这种“无缝”的接续运行,则必须在任务被中止时就把该任务的断点数据保存到堆栈中;而在被重新运行时,则要把堆栈中的这些断点数据在恢复到CPU的各个寄存器中,只有这样才能使被中止运行的任务在恢复运行时可以实现“无缝”接续运行。 与中断机制类似
任务调度 (好资料)_第2张图片
所以,一个被中止的任务能否正确的在断点处恢复运行, 其关键在于是否能够正确的在CPU各个寄存器中恢复断点数据;而能够恢复断点数据的关键是CPU的堆栈指针SP是否有正确的指向。 因此, 在系统中运行多个任务时,如果在恢复断点时用另一个任务的任务堆栈指针(存放在任务控制块OSTCBStkPtr)来改变CPU的堆栈指针SP,那么CPU运行的就不是刚才被中止的任务,而是另一个任务了,也就是实现任务切换了。当然为了防止被中止任务堆栈指针的丢失,别中止任务在保存断点时,要把当时CPU的SP的值保存到该任务控制块的成员OSTCBStkPtr中。
       综上所述,任务的切换就是断点数据的切换,断点数据的切换也就是CPU堆栈指针的切换
   被中止运行任务的堆栈指针要保护到该任务的任务控制块中,待运行任务的任务堆栈指针要由该任务控制块转存到CPU的SP中。
 
所以OSCtxSw()要一次完成下面7个动作
1.把被中止任务的断点指针保存到任务堆栈中
2.把CPU通用寄存器的内容保存到任务堆栈中
3把中止任务的任务堆栈指针当前值保存到该任务的任务控制块的OSTCBStkPtr中
4获得待运行任务的任务控制块
5使CPU通过任务控制块获得待运行任务的任务堆栈指针
6把待运行任务堆栈指针中通用寄存器的内容恢复到CPU的通用寄存器中
7使CPU获得待运行任务的断点指针(该指针是待运行任务上一次被调度器中止运行时保留在任务堆栈中)
 
 一个说明

       众所周知,CPU是按CPU中的一个特殊功能寄存器--程序指针PC的指向来运行程序的。或者说,只有使PC寄存器获得新任务的地址,才会使CPU运行新的任务。既然如此,对于被中止任务,应该把任务的断点指针(在PC寄存器中)压入堆栈;而对于待运行任务而言,应该把任务堆栈中上次任务被中止时存放在堆栈中的中断指针推入PC寄存器。但遗憾的是,目前的处理器一般没有对程序指针寄存器PC的入栈和出栈指令。   所以要想办法引发一次中断(或者一次调用),并让中断向量指向OSCtxSw()(其实这个函数就是中断服务程序),利用系统在跳转到中断服务程序时会自动把断点压入堆栈的功能,把断点指针送入堆栈,而利用中断返回指令,能把断点指针推入CPU的PC寄存器的功能,恢复待运行任务的断点,这样就可以实现断点的保存和恢复了

         由于任务切换时需要对CPU寄存器进行操作,因此在一般情况下,中断服务程序OSCtxSw()要用汇编来编写

     由什么来引发中断呢?

     这就是宏OS_TASK_SW()的作用了。如果使用微处理器具有软中断指令的话,可以在宏中封装一个软中断指令即可;如果使用的微处理器没有提供软中断指令,那么就可以尝试宏OS_TASK_SW()封装其他可以使PC等相关寄存器入栈的指令

http://zhangzhenyuan163.blog.163.com/blog/static/8581938920115632221162/

你可能感兴趣的:(任务调度 (好资料))