ucos---Scheduling(调度)

调度器,也称分发器,是负责决定接下来运行哪个任务。UCOS 是一个基于优先级的抢占式内核。如我们所见,每个任务都根据其重要性赋予一个优先级别。任务的优先级别依赖于其具体应用场景,另外,UCOS 支持同一优先级多个任务。

抢占意味着当事件发生,将响应的高优先级的任务切换为就绪状态,接着此任务立即获得 CPU的控制权。当前任务挂起,高优先级的新任务运行。

1 抢占调度

UCOS 处理事件发布有两种方式:直接发布和延迟发布。

1.1 直接发布

抢占调度---直接发布
  1. 一个低优先级的任务正在执行的时候发生了一个中断。(1)
  2. 如果中断处于使能,则依据 CPU 中断向量表将跳转到 ISR,执行中断服务程序。(2)
  3. 中断服务程序执行,通知响应的任务,切换到就绪状态。(3)
  4. ISR 执行完成后,UCOS 调用任务切换服务。(4)
  5. CPU 切换到执行优先级更高的就绪任务。(5)(6)
  6. 高优先级任务执行完成,切换到 UCOS 中,查询是否有另一个中断发生。(7)(8)
  7. 若没有中断发生,则 UCOS 切换到先前被中断任务继续执行。(9)(10)
  8. 先前被中断任务从中断处继续执行。(11)

1.2 延时发布

抢占调度---延时发布
  1. 此种方式是在 ISR 中,不会直接通知对应的等待事件的任务,而是将该事件放到一个队列中来处理。
  2. 当 ISR 完成后,则切换到UCOS中来工作。
  3. ISR 使得 ISR 处理任务切换为就绪状态,则 UCOS 切换到该任务。
  4. ISR 处理任务通知高优先级任务使其处于就绪状态,ISR队列所有中断处理完毕,并切换到高优先级就绪任务执行。

2 调度入口

  • 某一任务信号通知或发送消息到另一个任务
  • 某一任务调用 OSTimeDly() or OSTimeDlyHMSM()
  • 某一任务需要等待一个事件的发生,且此事件当前尚未发生。
  • 如果某一任务中止等待
  • 如果某一任务被新建
  • 若某一任务被删除
  • 若某一内核对象被删除
  • 某一任务的优先级被改变
  • 某一任务调用 OSTaskSuspend () 挂起本身
  • 某一任务被另一任务通知继续
  • 在 ISRs 嵌套的最后一个 ISR 执行完成
  • 调度锁解锁时
  • 某一任务调用 OSSchedRoundRobinYield() 放弃时间片
  • 用户调用 OSSched()

3 轮转调度

当两个或者更多的任务有相同的优先级时,UCOS 允许一个任务运行一个时间片后调度另外一个任务,这个过程称之为时间切片或轮转调度。如果某个任务不需要整个时间片,则它可以主动放弃 CPU 以便执行下一任务。UCOS 允许用户决定是否使能时间片轮转调度算法。

下图显示了一个轮转调度的样例,一共有 3 个优先级相同的任务处于就绪状态。为了方便例释,每四个时钟为一个时间片,图中加深的时钟线。


时间片轮转调度

(1)Task #3 正在执行,但是此时,发生了一个时钟中断,且 Task #3 的时间片尚未用尽。
(2)一个 4th 时钟中断发生,则 Task #3 的时间片耗尽
(3)UCOS 暂停 Task #3,切换到执行 Task #1
(4)Task #1 持续执行直到时间用完
(5)(6)(7)Task #3 执行过程中,通过调用 OSSchedRoundRobinYield() 决定放弃剩余时间片,这将会切换到下一个就绪任务。需要注意的是,当 UCOS 调度到 Task #1 时,重置时间片为 4 个滴答,以至于下一个时间片从这个点消耗 4 个时间片。
(8)Task #1 zhixing 执行整个时间片

用户可以通过调用 OSSchedRoundRobinCfg() 设置时间片大小。UCOS 也允许在创建任务时指定该任务自己的时间片。

3 调度原理

调度是通过调用 OSSched() 和 OSIntExit() 两个函数进行。OSSched() 是任务代码调用,而 OSIntExit() 是 ISR 中调用。两个都在可以再 os_core.c中发现。

下图是就绪队列的两个结构:


优先级就绪位图和就绪列表

3.1 OSSched()

以下是伪代码:

void OSSched(void)
{
    Disable interrupts;
    //确认没有从 ISR 中调用 OSSched()
    if(OSIntNestingCtr > 0)   
    {
        return;
    }
    //确认调度锁打开
    if(OSSchedLockNestingCtr > 0)  
    {
        return;
    }
   // 从OSPrioTbl[] 中获取最高优先级的就绪任务
    Get highest priority ready;     //(3)
   //获取待执行任务的 TCB指针,并从就绪列表中删除
    Get pointer to OS_TCB of next highest priority task;   //(4)
   //不允许同一任务切换
    if(OSTCBNHighRdyPtr != OSTCBCurPtr)     //5
    {
        perform task level context switch;      
    }
    Enable interrupts;
}

代码也表明次函数只能在任务级代码调用,在调度和上下文切换时需要禁止中断,因为该过程必须原子化。

3.2 OSIntExit()

以下是代码:

void  OSIntExit (void)
{
   CPU_SR_ALLOC();
  //Has the OS started?                           
   if (OSRunning != OS_STATE_OS_RUNNING) {               
       return;                                            
   }

   CPU_INT_DIS();
  /* Prevent OSIntNestingCtr from wrapping                  */
   if (OSIntNestingCtr == (OS_NESTING_CTR)0) {             
       CPU_INT_EN();
       return;
   }
   OSIntNestingCtr--;
   /* ISRs still nested?          */
   if (OSIntNestingCtr > (OS_NESTING_CTR)0) {             
       CPU_INT_EN();            /* Yes    */                           
       return;
   }
  /* Scheduler still locked?             */
   if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {       
       CPU_INT_EN();           /* Yes           */
       return;
   }
 /* Find highest priority                                  */
   OSPrioHighRdy   = OS_PrioGetHighest();     
 /* Get highest priority task ready-to-run                 */           
   OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;   
 /* Current task still the highest priority?               */
   if (OSTCBHighRdyPtr == OSTCBCurPtr) {         
             /* Yes            */        
       CPU_INT_EN();                         
       return;
   }

#if OS_CFG_TASK_PROFILE_EN > 0u
/* Inc. # of context switches for this new task           */
   OSTCBHighRdyPtr->CtxSwCtr++;                           
#endif
   /* Keep track of the total number of ctx switches         */
   OSTaskCtxSwCtr++;                                   

#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
   OS_TLS_TaskSw();
#endif
/* Perform interrupt level ctx switch                     */
   OSIntCtxSw();                                           
   CPU_INT_EN();
}

3.3 OS_SchedRoundRobin()

OS_SchedRoundRobin() 可能从 OSTimeTick() 或 OS_IntQTask() 中调用。

/*
***************************************************************************************
*              RUN ROUND-ROBIN SCHEDULING ALGORITHM
*
* Description: This function is called on every tick to determine if a new task at the same priority needs to execute.
*
*
* Arguments  : p_rdy_list    is a pointer to the OS_RDY_LIST entry of the ready list at the current priority
*              ----------
*
* Returns    : none
*
* Note(s)    : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
************************************************************************************************************************
*/

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
void  OS_SchedRoundRobin (OS_RDY_LIST  *p_rdy_list)
{
    OS_TCB   *p_tcb;
    CPU_SR_ALLOC();
 /* Make sure round-robin has been enabled                 */
    if (OSSchedRoundRobinEn != DEF_TRUE) {                 
        return;
    }

    CPU_CRITICAL_ENTER();
    p_tcb = p_rdy_list->HeadPtr;                         
    if (p_tcb == (OS_TCB *)0) {
        CPU_CRITICAL_EXIT();
        return;
    }

    if (p_tcb == &OSIdleTaskTCB) {
        CPU_CRITICAL_EXIT();
        return;
    }
   /* Decrement time quanta counter                          */
    if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {
        p_tcb->TimeQuantaCtr--;
    }
 /* Task not done with its time quanta                     */
    if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {               
        CPU_CRITICAL_EXIT();
        return;
    }
 /* See if it's time to time slice current task            */
    if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {      
  /* ... only if multiple tasks at same priority            */    
        CPU_CRITICAL_EXIT();                              
        return;
    }
/* Can't round-robin if the scheduler is locked           */
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {        
        CPU_CRITICAL_EXIT();
        return;
    }
/* Move current OS_TCB to the end of the list             */
    OS_RdyListMoveHeadToTail(p_rdy_list);  
 /* Point to new OS_TCB at head of the list                */                 
    p_tcb = p_rdy_list->HeadPtr;         
  /* See if we need to use the default time slice           */                  
    if (p_tcb->TimeQuanta == (OS_TICK)0) {                
        p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
    } else {
 /* Load time slice counter with new time                  */
        p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;          
    }
    CPU_CRITICAL_EXIT();
}
#endif
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容

  • 本文参考《Mac OS X and iOS Internals: To the Apple’s Core》 by ...
    darcy87阅读 11,303评论 0 22
  • 今天是什么日子:财神节 起床:6:00 就寝:11:00 天气:晴 心情:还不错 纪念日:无 任务清单 昨日完成的...
    捷云飘逸阅读 82评论 0 1
  • 我前两天刚入职一家公司,做运营工作,由于城市是小地方很多人都问我到底怎样是运营,刚开始我都耐心的解释半天,最后我无...
    Xmotel阅读 844评论 0 13
  • 昨天是我爸去世的的第三七,实在不想写什么简书,昨天什么都没有做,心情和天气一样的沉闷,在家人面前心里流泪脸上还是跟...
    张靖一雯阅读 199评论 0 0