👟RTOS原理与实现04:任务管理模块
2023-6-3
| 2024-7-6
0  |  阅读时长 0 分钟
type
status
password
date
slug
summary
category
URL
tags
icon

1. 任务的挂起与唤醒

1.1 任务状态切换

notion image

1.1.1 关于就绪态与运行态

  • 就绪态与运行态:调用tTaskInit函数创建的任务状态被默认设置为就绪态(TINYOS_TASK_STATE_READY),而其中优先级最高的任务队列中的第1个任务将被运行,即进入运行态。
    • 但是运行态本身是没有特殊标记的,即就绪态的任务在获得CPU使用权后即进入运行态
      这点和Linux类似,就绪态和运行态的任务均标识为TASK_RUNNING
  • 挂起状态:任务挂起就是暂时禁止任务占用CPU运行,简单来说就是无条件暂停任务运行。

1.1.2 任务进入挂起状态的方法

  1. 任务主动调用挂起函数
  1. 被其他任务强制挂起(由其他任务调用挂起函数)

1.1.3 挂起态的使用场景

当任务需要占用资源时(e.g. 信号量),如果资源不可用,就需要将任务置为挂起态;当资源就位时,需要将挂起的任务恢复为就绪态。

1.2 任务挂起与唤醒设计原理

任务挂起:将任务从就绪队列移除。
任务挂起(不允许挂起延时任务)
任务挂起(不允许挂起延时任务)
任务唤醒:将挂起的任务加入就绪队列
任务唤醒
任务唤醒
说明1:可以用链表将挂起的任务组织起来,但是其实无此必要,因为调用挂起与唤醒函数时都会传递任务结构指针(tTask *)
说明2:本章节仅支持将就绪任务的挂起,并未实现延时任务的挂起,但是从原理上二者都是支持的,只是延时任务挂起的实现复杂一些(e.g. 需要判断挂起过程中时间的流逝)

1.3 设计实现

notion image

1.3.1 添加挂起计数器

在任务结构中添加任务挂起计数器,使用计数器是为了支持任务被多次挂起;相应地,tTaskInit函数中将suspendCount字段初始化为0

1.3.2 tTaskSuspend函数(挂起函数)

💡
因为挂起没有从延时队列中删除,所以会仅需进行计数。那么会导致一个结果就是延时结束后,任务会添加到就绪队列。只不过任务状态可能还是挂起,但任务会被运行。

1.3.3 tTaskResume函数(唤醒函数)

2. 任务的删除

2.1 任务删除行为

2.1.1 将任务从所在队列移除

  • 如果任务处于就绪态 / 运行态,则将任务从就绪队列移除
  • 如果任务处于延时状态,则将任务从延时队列移除
  • 如果任务处于挂起态,则只需要释放任务占用的资源。挂起状态直接删除
    • notion image

2.1.2 释放任务占用资源

在删除任务时,还需要安全地释放任务所打开 / 占用的资源。例如:当任务A删除任务B时,必须确保任务B占用的资源被释放
notion image
 

2.2 安全删除原理

2.2.1 由谁删除

只有任务自身最清楚自己使用的资源,所以在删除过程中应该让任务自行释放资源
notion image

2.2.2 删除方式

  • 安全删除方式之一:设置清理回调函数,在强制删除时调用。删除步骤如下
      1. 开始删除任务B
      1. 调用任务B的清理回调函数(可以注册在任务结构中)
      1. 清理函数释放 / 关闭资源
      1. 继续删除任务B
      notion image
  • 安全删除方式之二:设置删除请求标志,由任务自己决定何时删除。删除步骤如下,
      1. 任务A设置删除请求标记
      1. 任务B根据需要检查删除请求标记
      1. 任务B自行进行资源清理
      1. 如果任务B注册了清理回调函数,则调用之
      1. 继续删除任务B
      notion image

2.2.3 删除方式对比

删除方式
强制删除
请求删除
删除时机
调用时即删除
由被删除任务自行决定
易用性
较差 需要在清理函数中判断删除时当前占用了哪些资源
较好 处理删除请求时就能知道需要清理哪些资源
缺点
有些情况下,删除时无法完成清理操作(e.g. 在调用第三方库时被删除)
仅仅设置删除请求,具体何时删除不确定,有可能任务不处理删除请求或者很长时间之后才处理

2.3 设计实现

2.3.1 任务结构增设任务删除相关字段

在增设相关字段后,需要在tTaskInit函数中对其进行初始化

2.3.2 回调注册函数

在创建任务时,将任务删除函数设置为空,因此需要提供函数设置该字段(当然,也可以在tTaskInit函数中增加相关参数进行设置)

2.3.3 添加删除任务函数队列

如前所述,在删除任务时任务可能处于就绪态或延时状态,所以提供函数分别用于将任务从相关队列移除

2.3.4 添加请求删除函数(方式二)

根据请求删除的处理流程,分别需要请求删除设置函数、请求删除检查函数和任务自我删除函数
💡
说明:tTaskDeleteSelf函数的临界区保护
因为此处先将任务从就绪列表中删除,如果在调用清理回调函数的过程中被调度走,则无法再返回

2.3.5 添加强制删除相关函数

强制删除任务时,即可以删除其他任务也可以删除自己

2.3.6 任务设置(删除任务的回调函数)

测试代码设置4个任务,其中,
  • task 1 & task 2组:task 1设置任务删除回调函数,task2强制删除task 1
    • task 3 & task 4组:task 4请求删除task 3,task 3检查任务删除请求标志并删除自己
      启动任务时将要被删除的任务设为高优先级,用于模拟在任务被删除前已经开始运行

      3. 任务状态查询

      3.1 状态结构定义

      定义tTaskInfo结构用于描述状态信息,可见状态信息相关字段均源自任务结构,这也就是获取任务状态的含义

      3.2 状态信息获取

      3.2.1 添加获取任务状态函数

      3.2.2 为什么不直接访问任务结构获取状态

      tTaskGetInfo函数的实现就是进入临界区,然后从指定的任务结构中拷贝相关字段到tTaskInfo结构中,那么我们为什么不直接访问任务结构获取状态呢 ?
      主要有以下2个原因:
      1. 引入tTaskInfo结构可以向tTaskGetInfo函数调用者隐藏tTask结构的细节
      1. 由于tTaskGetInfo函数是在临界区中获取任务状态,所以可以完整获取某一时刻任务的所有状态信息;而直接访问tTask结构获取任务信息的过程可能被打断
      notion image
    • RTOS
    • RTOS原理与实现03:内核核心实现RTOS原理与实现05:事件控制块实现
      Loading...
      目录