实时操作系统任务调度

最近看了一些实时操作系统的源码,关于任务调度是实时操作系统的重要组成部分,但是何时发生调度,怎样才能发生调度却不是非常的清晰,书中一本而言所说的都是“如果有更高优先级任务就绪,就会发生调度”,这会让很多的读者产生很大的歧义:
在当前的任务中,并没有关于就绪表等全局变量的访问,当前的任务也有自己的堆栈空间,我并不知道是否有更高优先级的任务就绪,之所以产生这些疑惑是没有搞清楚什么时候发生调度,怎么知道需要调度。 当前运行的任务,一般而言就是所谓的最高优先级的任务,在没有访问一系列全局变量的过程中,内核又是如何知道存在一个更高优先级的任务被就绪了呢?
 
一般而言,对于抢占型实时内核,一般在同步、或者通信的过程中会主动的调用调度函数,或者任务的挂起函数中使用调度函数,其他的函数中并没有发现其他的调度函数,而且这种情况下都是手动的调度任务,那么在没有这些函数的情况下,实时操作系统中内核是如何知道需要调度的呢?
 
我仔细查找了一些资料,别人总结了一些操作系统发生调度的原因如下:
  (1)正在执行的进程执行完毕。这时,如果不选择新的就绪进程执行,将浪费处理机资源。
  (2)执行中进程自己调用阻塞原语将白己阻塞起来进入睡眠等状态。
  (3)执行中进程调用了P原语操作,从而因资源不足而被阻塞;或调用了v原语操作激活了等待资源的进程队列。
  (4)执行中进程提出I/O请求后被阻塞。
  (5)在分时系统中时间片已经用完。
  (6)在执行完系统调用等系统程序后返回用户进程时,这时可看作系统进程执行完毕,从而可调度选择一新的用户进程执行。
  以上都是在可剥夺方式下的引起进程调度的原因。在CPU执行方式是可剥夺时.还有
  (7)就绪队列中的某进程的优先级变得高于当前执行进程的优先级,从而也将引发进程调度。
我对比了在实时操作系统中经常使用的调度方式发现,原因(2)、(3)、(7)是主要的原因,其他的一般在实时操作系统中很难找到。但是这还是不能回答什么时候发生调度这个问题。
 
我认为在实时操作系统中发生调度的主要有两个部分:
(1)自身需要睡眠等待,必须手动的调用调度函数(信息量,或者通信机制)。
(2)发生中断过,当执行完中断服务函数以后,需要重新调度。
 
其中原因(2)是我们在分析实时操作系统中实时性能的主要因素,很多人又会有很多的疑问,如果操作系统中很少使用中断, 实质上在实时系统中必须存在的一个中断就是时间节拍中断,这个中断的存在就能保证实时操作系统的实时型。这个时间节拍选择也是设计过程中必须注意的。我们可以参看uC/OS-II的时间节拍代码,其中完成了所有对非任务挂起的任务的就绪操作(时间到期),这时也就知道了那个任务需要我们调度。在其他的中断服务函数执行完成以后也就需要那个任务需要被执行,进而实现了实时操作。

点击(此处)折叠或打开

  1. void OSTimeTick (void)
  2. {
  3. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  4.     OS_CPU_SR cpu_sr;
  5. #endif
  6.     OS_TCB *ptcb;

  7.     OSTimeTickHook(); /* Call user definable hook */
  8. #if OS_TIME_GET_SET_EN > 0 
  9.     OS_ENTER_CRITICAL(); /* Update the 32-bit tick counter */
  10.     OSTime++;
  11.     OS_EXIT_CRITICAL();
  12. #endif
  13.     if (OSRunning == TRUE) { 
  14.         ptcb = OSTCBList; /* Point at first TCB in TCB list */
  15.         while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { /* Go through all TCBs in TCB list */
  16.             OS_ENTER_CRITICAL();
  17.             if (ptcb->OSTCBDly != 0) {                     /* Delayed or waiting for event with TO*/
  18.                 if (--ptcb->OSTCBDly == 0) { /* Decrement nbr of ticks to end of delay */
  19.                     if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
  20.                         OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make task R-to-(timed out)*/
  21.                         OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  22.                     } else {
  23.                             /* Yes, Leave 1 tick to prevent ... */
  24.                         ptcb->OSTCBDly = 1; /* ... loosing the task when the ... */
  25.                     } /* ... suspension is removed. */
  26.                 }
  27.             }
  28.             ptcb = ptcb->OSTCBNext; /* Point at next TCB in TCB list */
  29.             OS_EXIT_CRITICAL();
  30.         }
  31.     }
  32. }
从上面的代码中我们可以知道每个任务都会被扫描一次,检测是否能够就绪,如果能够就绪就将就绪表中的值设置,这样也就知道了是否有更高优先级的任务就绪,是否需要调度操作。因为时间节拍中断的不断发生就能保证最高优先级任务的发生。因此时间节拍中断函数是在实时操作系统中非常重要的函数之一。当然任务之间切换以及在中断中切换到新的任务中的切换代码也是非常重要的,但是这些一般涉及到CPU寄存器的值,需要汇编代码实现。
因为中断完成以后很多的任务可能因为信号量等信息的释放已经就绪,这时候必然需要任务的调度操作,这时候也就知道了那个任务是最高优先级的,那个任务应该被执行。这时也就是发生调度的时刻。
 
在UC/OS-II中通常采用关闭中断的方式进入临界区,因为关闭了中断,所有的中断服务函数都不会被执行,也就不会发生任务的调度。那么只有一个情况才会发生调度,也就是任务自身需要睡眠,手动选择调度函数,但是在临界区中不应该发生睡眠等,因此也就不可能手动调度,因此所有发生调度的可能都被清除了,这样也就保证了临界区代码的安全性。

浅谈实时操作系统任务调度

  (2011-06-10 18:32:27)
转载
  分类: 作业

一、1、 调度用来确定多任务环境下任务执行的顺序在获得CPU资源能够执行的时间长度

    2、 操作系统通过一个度程序来实现调度功能。

   调度程序以函数的形式存在,用来实现操作系统的调度算法。调度程序本身并不是一个任务,是一个函数调用,可在内核的各个部分进行调用。

    3、调用调度程序的具体位置又被称为是一个调度点scheduling point),调度点通常处于以下位置中断服务程序的结束位置;任务因等待资源而处于等待状态;任务处于就绪状态时等。

二、调度算法

    从理论上来说,最优调度只有在能够完全获知所有任务在处理、同步和通信方面的需求,以及硬件的处理和时间特性的基础上才能实现。实际的应用很难实现,特别是需要获知的信息处于动态变化的情况下。即使在这些需要的信息都是可以预见的情况下,常用的调度问题仍然是一个NP难题。调度的复杂性将随调度需要考的任务和约束特性的数量呈现出指数增长。调度算法不能很好地适应系统负载和硬件资源不断增长的系统。当然,这并不意味着调度算法不能解决只有少量、定义好的任务的应用的需求。

   嵌入式实时操作系统兼有嵌入式和实时性的特点。作为一种嵌入式操作系统,它具有嵌入式软件共有的可裁剪、低资源、低功耗等特点;作为实时操作系统除了要满足应用的功能需求以外,更重要的是还要满足应用提出的实时性要求。实时操作系统所遵循的最重要的# #设计原则是:采用各种算法和策略始终保证系统行为的可预测性。实时操作系统的首要任务是调动一切可利用的资源完成实时控制任务。如何使任务集内各任务满足各自的时限,使系统得以正常、高效率工作的任务调度算法一直是实时系统领域内研究的焦点。根据其应用领域及追求精简、高设角度的不同,任务调度算法从简单的合理安排任务循环,发展到基于优先级的速率单调调(RMs)、最早时限优先(EDF)等算法。任务调度算法的好坏以及执行效率直接关系到嵌入式内核的应用范围及实时性程度。

1、各种实时操作系统的实时调度算法可以分为如下三种类别

基于优先级的调度算法(Priority-driven scheduling-PD)、基于CPU使用比例的共享式的调度算法(Share-drivescheduling-SD)、以及基于时间的进程调度算法(Time—driven schedulinq-TD),下面对第一种调度算法进行重点介绍。

   基于优先级的调度算法给每个进程分配一个优先级,在每次进程调度时,调度器总是调度那个具有最高优先级的任务来执行。根据不同的优先级分配方法,基于优先级的调度算
法可以分为如下两种类型

1.1 静态调度
    静态调度是在系统开始运行前进行调度的,严格的静态调度在系统运行时无法对任务进行重新调度。静态调度的目标是把任务分配到各个处理机,并对每一处理机给出所要运行任务的静态运行顺序。静态调度算法实现简单,调度的额外开销小,在系统超载时可预测性好。但也具有很大的局限性,例如资源利用率低、受系统支持的优先级个数限制以及灵活性和自适应性差等。

1.2 动态调度
    在嵌入式实时系统中,动态调度依赖于任务的优先级。优先级可以静态分配或者依据不同的特征参数,如截止时问、空闲时间或关键性(即任务的重要程度)等进行动态分配。动态
调度可以是抢占式的或非抢占式的。当检查到一事件时,动态抢占式算法立即决定是运行与此事件相关的任务,或继续执行当前的任务;对于动态非抢占式算法,它仅仅知道有另一
个任务可以运行,在当前任务结束后,它才在就绪的任务中选择一个来运行。

三、调度算法的选择 嵌入式实时系统中资源是非常有限的,所以开销要尽可能小。开销主要包括运行开销和调度开销。运行开销与队列分析和从调度队列中增加、删除任务相关。每个任务在一个调度周期内至少被阻塞和唤醒一次,所以任务调度器在一个周期内不得不对一个任务进行两次选择。静态算法根据任务的执行频率设置优先级,有较小的运行开销,但执行频率最高的任务不一定是最重要的。EDF算法中则是对整个任务列表的调度开销进行全面比较,选择最高优先级任务进行调度,有较小的调度开销,但对多个任务具有同一优先级的情况考虑不足。基于优先级的调度算法在实时进程调度中使用很广泛,静态优先级调度算法根据应用的属性来分配优先级,其可控性较强,而动态优先级调度算法在资源分配和调度时具有更大的灵活性。如果结合这两种算法的优点,扬长避短,就能够对实时任务进行更合理、更高效的任务调度。利用最著名的动态优先级调度算法一EDF算法的高CPU利用率、可调度较大的任务集的特点,结合静态优先级调度算法的可控性就形成了一种新的调度算法-NEDF、调度算法(New Earliest Dead—line First)。

 NEDF算法概述
NEDF算法以任务的截止期限作为任务调度的首要指标,但不是唯一的指标。当两任务的截止期限在一定的IM值范围内时,根据任务的优先级来决定要运行的任务,这时以任务的静态优先级来选择任务,一定程度上增强了算法的可控性。确定任务的静态优先级,主要依据有以下几个。
(1)执行时间
以执行时间为依据,执行时间越短,静态优先级越高。
(2)任务周期
以任务周期为依据,任务周期越短,静态优先级越高。
(3)任务的CPU利用率
任务的CPU利用率为任务执行时间与任务周期的比值(生)。仟各的CPU利基于Linux的实时操作系统研究用率越高,静态优先级越高。(4)任务紧急程度根据任务的紧急程度,人为安排任务的优先级。任务越紧急,静态优先级越高。
 算法说明
先假定任务的优先级均不相同,则在某个调度时刻t,NEDF算法先查找距截止期限最近的任务。这时,可能有多个任务的截止期限相等或较为接近。如果截止期限相等,则选择
高优先级的任务运行。如果截止期限均不相等,且最小截止期限比次小截止期限小许多,则选择最小截止期限的任务运行。若最小截止期限与次小截止期限的差值在一定的IM值范围
内,则选择高优先级的任务运行。截止期限IM 值的设定应保证最高优先级任务能够如期完成,一般可取最小相对截止期限的值,以确保在最小相对截止期限的周期范围内,最高优先
级任务能够优先运行。


你可能感兴趣的:(嵌入式,uC/OS-II,操作系统,任务调度,嵌入式系统)