任务管理与调度

本文分享自中移OneOS微信公众号《任务管理与调度》。

实时操作系统对性能及响应时间的要求比较高,为了满足实时性指标,需要把一个复杂的应用分解成多个小的、可调度的、序列化的单元,并且保证分解的单元能正确的按照预期的设计执行。

<内核对象框架>

<内核对象链表结构>

任务的功能特点

在物联网操作系统中,任务是最基本的调度单位。任务的属性包含执行的运行环境(也称为上下文,包含各个变量和数据,所有的寄存器值、堆栈、内存信息等)、任务的优先级、运行时间等,实时和重要的任务可设置相对较高的优先级,其他任务可以设置较低的优先级。当任务切换时,调度器会先将当前任务上下文保存起来,当切回到这个任务时,再将该任务的上下文信息恢复,这样保证单个任务像是以独占CPU的方式在运行而不会丢失数据。

系统运行过程中有以下4类比较常见的任务切换场景:

(1)不同优先级的任务之间,任务调度器是抢占式的,当高优先级的任务就绪,总是抢占低优先级任务的CPU使用权。
(2)同等优先级的任务之间,任务调度器是轮询式的,每个任务初始化时规定了执行的时间片数量,时间消耗完后切换到另外一个同等优先级的任务。
(3)当前任务因等待某个资源而挂起,任务调度器选择就绪状态的最高优先级任务运行。
(4)如果是中断服务程序使一个更高优先级的任务满足运行条件,中断完成时,被中断的任务挂起,优先级高的任务开始运行。

任务的工作机制

(1) 任务的优先级

表示任务放入调度列表中是否优先被调度,系统最多支持256个任务优先级(0~255),0为最高优先级,值越小优先级越高。因为调度列表需要占用部分资源,如果系统资源不足,可以在系统配置中选择8个或32个优先级。操作系统是抢占式的,只要有更高优先级的任务就绪,当前任务将立刻被换出。

(2) 时间片

优先级相同的任务采用时间片轮转的方式进行调度。任务创建时规定的时间片限制任务单次调度执行的最长时间,其单位是一个系统节拍(tick)。例如,有3个优先级相同的就绪态任务A、B和C,A任务的时间片设置为1,B任务的时间片设置为2,C任务的时间片设置为3,如果系统中无更高优先级的就绪态任务,会在这3个任务间来回切换执行,如下图。

<任务运行时间片示意图>

(3) 基本结构

任务控制块是进行任务管理的基本数据结构,由结构体struct os_task表示,它会存放任务运行及调度的一些信息,详细定义如下:


struct os_task
{
    os_object_t      parent                       /* object父结构体 */
    os_list_node_t   task_list;                  /* 任务链表 */
    void             *sp;                         /* 栈指针 */
    void             *entry;                      /* 任务入口函数 */
    void             *parameter;                  /* 入口函数参数 */
    void             *stack_addr;                 /* 栈地址 */
    os_uint32_t      stack_size;                  /* 栈大小 */
    os_err_t        error;                        /* 错误码 */
    os_uint8_t      stat;                         /* 任务状态 */
    os_uint8_t      current_priority;            /* 当前优先级 */
    os_uint8_t      init_priority;               /* 初始化优先级 */
    os_uint32_t      number_mask;
    . . . . . .
    os_ubase_t      init_tick;                   /* 初始化占用系统tick数 */
    os_ubase_t      remaining_tick;              /* 剩余系统tick数 */
    os_timer_t       task_timer;                  /* 任务定时器 */
    void (*cleanup)(os_task_handle_t *handle);  /* 任务退出清理函数 */
    os_uint32_t      user_data;                   /* 用户自定义数据 */
};

task_list是任务链表指针,用于把任务连接到相同优先级的任务链表;

stack_addr是任务栈空间,由任务创建时传入或由系统分配;

init_priority是任务创建时指定的任务优先级,在任务运行过程当中是不会被改变的;

current_priority是任务运行过程的优先级,一般情况下与init_priority相等,当发生优先级反转时会发生变化;

cleanup是任务清理函数,在任务退出时被空闲任务调用。

(4) 状态迁移

在系统运行过程中,任务有多种不同的运行状态,包含初始状态、就绪状态、运行状态、挂起状态、关闭状态,任务调度器会根据任务的运行情况和当前系统的状态来调整任务状态,如表所示。

任务状态

详细描述

初始状态

创建了任务但是还未调用开始执行接口函数时就处于初始状态,此时任务不参与调度。

就绪状态

此时任务按照优先级排队,等待被调度;一旦运行状态的任务需要切换,调度器会查找最高优先级的就绪状态任务运行。

运行状态

正在占用CPU运行。

挂起状态

因为需要的资源不可用或者任务主动延时一段时间而进入挂起状态,此时任务不参与调度。

关闭状态

任务执行结束时将进入关闭状态,不参与调度。

各状态之间的迁移如下图。

<任务状态迁移示意图>

任务管理接口设计

(1)创建任务

(2)销毁任务

(3)启动任务

(4)获取当前任务

(5)换出任务

(6)休眠任务

(7)挂起任务

(8)恢复任务

(9)控制任务

(10)设置任务空闲回调函数

(11)删除任务空闲回调函数

(12)设置任务调度回调函数

OneOS是中国移动针对物联网领域推出的轻量级操作系统,具有可裁剪、跨平台、低功耗、高安全等特点,支持ARM Cortex-M/R/A、MIPS、RISC-V等主流CPU架构,兼容POSIX、CMSIS等标准接口,支持Micropython语言开发,提供图形化开发工具,能够有效提高开发效率并降低开发成本,帮助客户开发稳定可靠、安全易用的物联网应用。 官网地址:https://os.iot.10086.cn/
OneOS软件地址:http://www.oschina.net/p/cmcc-oneos
OneOS项目地址:https://gitee.com/cmcc-oneos/OneOS
OneOS技术交流群:158631242

{{o.name}}
{{m.name}}

猜你喜欢

转载自my.oschina.net/u/5443273/blog/5448510