首页 > 编程语言 > 详细

SylixOS 线程调度浅析

时间:2017-02-14 22:20:21      阅读:184      评论:0      收藏:0      [点我收藏+]
  1. 概念

    在SylixOS中,在就绪线程和运行线程之间还存在候选运行线程。线程就绪后会被放置到就绪表中,而最需要运行(优先级最高)的线程会被放置到候选表,正常情况下CPU当前任务结束后,会运行候选表里的线程。

  2. 就绪表

    就绪表存放了SylixOS中除了"候选表中的线程"外,所有就绪没运行的线程。

  3. 候选表

    每一个CPU的结构体里面都有一个候选运行表,每一个候选表里最多有一个候选运行线程。候选运行表结构如程序清单 11所示。

    程序清单 11 候选运行表结构

    /*********************************************************************************************************

    候选运行表结构

    *********************************************************************************************************/

    #ifdef __SYLIXOS_KERNEL

     

    typedefstruct {

    volatilePLW_CLASS_TCBCAND_ptcbCand; /* 候选运行线程 */

    volatileBOOLCAND_bNeedRotate; /* 可能产生了优先级卷绕 */

    } LW_CLASS_CAND;

    typedefLW_CLASS_CAND *PLW_CLASS_CAND;

  4. 优先级卷绕

    如图 11所示,优先级卷绕是CPU结构体里面的候选表里的标志位CAND_bNeedRotate。

    技术分享

    图 11 候选运行表基本操作

  5. 优先级卷绕的产生

    当候选表不为空时,有一个优先级高于"候选表中线程"的线程就绪时,会产生优先级卷绕并将CPU的优先级卷绕标志位设置为1。具体流程如图 12所示。

    技术分享

    图 12 优先级卷绕产生的流程

     

  6. 线程调度

    系统主要在退出内核和退出中断时尝试进行线程调度。尝试进行线程调度的主要函数有:__kernelExit函数、__kernelExitIrq函数、__kernelSched函数和__kernelSchedInt函数。这里以__kernelExit函数为例介绍线程调度。

  7. 线程调度流程

    SylixOS线程调度流程如图 21所示。

    技术分享

    图 21 线程调度流程

  8. 尝试调度

    尝试调度,检查当前执行线程能否调度。(中断中或者在内核中执行, 不允许调度;当前线程就绪且被锁定, 不允许调度。)如程序清单 21所示。

    程序清单 21 _SchedGetCand函数

    PLW_CLASS_TCB_SchedGetCand (PLW_CLASS_CPUpcpuCur, ULONGulCurMaxLock)

    {

    if (!__COULD_SCHED(pcpuCur, ulCurMaxLock)) { /* 当前执行线程不能调度 */

    return (pcpuCur->CPU_ptcbTCBCur);

     

    } else { /* 可以执行线程切换 */

    if (LW_CAND_ROT(pcpuCur)) { /* 判断是否产生优先级卷绕 */

    _CandTableUpdate(pcpuCur);

    }

    return (LW_CAND_TCB(pcpuCur));

    }

    }

     

    1. 如果当前执行线程不能调度,继续运行当前线程,不产生调度。
    2. 如果当前执行线程能调度,继续判断是否产生了优先级卷绕。
  9. 优先级卷绕处理

    优先级卷绕的处理,如程序清单 22所示。

    第一步,如果产生了优先级卷绕,判断候选表是否为空。

    第二步,如果候选表不为空,判断就绪线程是否存在更加需要运行的线程。

    第三步,如果存在更加需要运行的线程,清空候选表(被清空的线程,会被插到对应就绪表的头部,下次优先调用),重新选择一个更需要运行的线程放入候选表,进行线程上下文切换,执行候选表中线程。

    程序清单 22 优先级就卷绕处理函数

    VOID_CandTableUpdate (PLW_CLASS_CPUpcpu)

    {

    UINT8ucPriority;

    REGISTERPLW_CLASS_TCBptcbCand;

    PLW_CLASS_PCBBMAPppcbbmap;

    BOOLbNeedRotate = LW_FALSE;

     

    if (!LW_CPU_IS_ACTIVE(pcpu)) { /* CPU 必须为激活状态 */

    return;

    }

     

    ptcbCand = LW_CAND_TCB(pcpu);

    if (ptcbCand == LW_NULL) { /* 当前没有候选线程 */

    _CandTableFill(pcpu);

    goto__update_done;

    }

     

    ppcbbmap = _SchedSeekPriority(pcpu, &ucPriority); /* 当前就绪表中最高优先级 */

    if (ppcbbmap == LW_NULL) {

    LW_CAND_ROT(pcpu) = LW_FALSE; /* 清除优先级卷绕标志 */

    return;

    }

     

    if (ptcbCand->TCB_usSchedCounter == 0) { /* 已经没有时间片了 */

    if (LW_PRIO_IS_HIGH_OR_EQU(ucPriority,

    ptcbCand->TCB_ucPriority)) { /* 是否需要轮转 */

    bNeedRotate = LW_TRUE;

    }

    } else {

    if (LW_PRIO_IS_HIGH(ucPriority,

    ptcbCand->TCB_ucPriority)) {

    bNeedRotate = LW_TRUE;

    }

    }

     

    if (bNeedRotate) { /* 存在更需要运行的线程 */

    _CandTableEmpty(pcpu); /* 清空候选表 */

    _CandTableResel(pcpu, ppcbbmap, ucPriority); /* 重新选择任务执行 */

    }

     

    __update_done:

    LW_CAND_ROT(pcpu) = LW_FALSE; /* 清除优先级卷绕标志 */

    }

     


SylixOS 线程调度浅析

原文:http://12558316.blog.51cto.com/12548316/1897784

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!