type
status
password
date
slug
summary
category
URL
tags
icon
1. 任务的挂起与唤醒
1.1 任务状态切换
1.1.1 关于就绪态与运行态
- 就绪态与运行态:调用tTaskInit函数创建的任务状态被默认设置为就绪态(TINYOS_TASK_STATE_READY),而其中优先级最高的任务队列中的第1个任务将被运行,即进入运行态。
但是运行态本身是没有特殊标记的,即就绪态的任务在获得CPU使用权后即进入运行态
这点和Linux类似,就绪态和运行态的任务均标识为TASK_RUNNING
- 挂起状态:任务挂起就是暂时禁止任务占用CPU运行,简单来说就是无条件暂停任务运行。
1.1.2 任务进入挂起状态的方法
- 任务主动调用挂起函数
- 被其他任务强制挂起(由其他任务调用挂起函数)
1.1.3 挂起态的使用场景
当任务需要占用资源时(e.g. 信号量),如果资源不可用,就需要将任务置为挂起态;当资源就位时,需要将挂起的任务恢复为就绪态。
1.2 任务挂起与唤醒设计原理
任务挂起:将任务从就绪队列移除。
任务唤醒:将挂起的任务加入就绪队列
说明1:可以用链表将挂起的任务组织起来,但是其实无此必要,因为调用挂起与唤醒函数时都会传递任务结构指针(tTask *)
说明2:本章节仅支持将就绪任务的挂起,并未实现延时任务的挂起,但是从原理上二者都是支持的,只是延时任务挂起的实现复杂一些(e.g. 需要判断挂起过程中时间的流逝)
1.3 设计实现
1.3.1 添加挂起计数器
在任务结构中添加任务挂起计数器,使用计数器是为了支持任务被多次挂起;相应地,tTaskInit函数中将suspendCount字段初始化为0
1.3.2 tTaskSuspend函数(挂起函数)
因为挂起没有从延时队列中删除,所以会仅需进行计数。那么会导致一个结果就是延时结束后,任务会添加到就绪队列。只不过任务状态可能还是挂起,但任务会被运行。
1.3.3 tTaskResume函数(唤醒函数)
2. 任务的删除
2.1 任务删除行为
2.1.1 将任务从所在队列移除
- 如果任务处于就绪态 / 运行态,则将任务从就绪队列移除
- 如果任务处于延时状态,则将任务从延时队列移除
- 如果任务处于挂起态,则只需要释放任务占用的资源。挂起状态直接删除
2.1.2 释放任务占用资源
在删除任务时,还需要安全地释放任务所打开 / 占用的资源。例如:当任务A删除任务B时,必须确保任务B占用的资源被释放
2.2 安全删除原理
2.2.1 由谁删除
只有任务自身最清楚自己使用的资源,所以在删除过程中应该让任务自行释放资源
2.2.2 删除方式
- 安全删除方式之一:设置清理回调函数,在强制删除时调用。删除步骤如下
- 开始删除任务B
- 调用任务B的清理回调函数(可以注册在任务结构中)
- 清理函数释放 / 关闭资源
- 继续删除任务B
- 安全删除方式之二:设置删除请求标志,由任务自己决定何时删除。删除步骤如下,
- 任务A设置删除请求标记
- 任务B根据需要检查删除请求标记
- 任务B自行进行资源清理
- 如果任务B注册了清理回调函数,则调用之
- 继续删除任务B
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个原因:
- 引入tTaskInfo结构可以向tTaskGetInfo函数调用者隐藏tTask结构的细节
- 由于tTaskGetInfo函数是在临界区中获取任务状态,所以可以完整获取某一时刻任务的所有状态信息;而直接访问tTask结构获取任务信息的过程可能被打断