RTOS任务管理模块
当前任务状态转换图
任务的挂起
概念:展示禁止任务占用CPU运行,也就是无条件暂停任务运行,增加了挂起状态的任务状态切换图:
实现
- 添加挂起计数器:记录任务被挂起的次数
编写挂起函数与唤醒函数: ```c void taskSuspend(task_t* task) { uint32_t st = enterCritical();
if (task->state & TASK_STATUS_DELAY) { leaveCritical(st); return; }
if (task->suspendCounter++ == 0) { taskSched2Unready(task); task->state |= TASK_STATUS_SUSPEND; if (task == currentTask) { taskSched(); } }
leaveCritical(st); }
void taskWakeUp(task_t* task) { uint32_t st = enterCritical();
1
2
3
4
5
6
7
8
9
if (task->state & TASK_STATUS_SUSPEND) {
if (--task->suspendCounter == 0) {
task->state &= ~TASK_STATUS_SUSPEND;
taskSched2Ready(task);
taskSched();
}
}
leaveCritical(st); } ```
任务的删除
- 将任务从所在的队列删除
- 释放/关闭任务占用的资源(已分配的存储空间、已打开的硬件设备、已创建的内核对象等等)
如何安全的删除
只有任务自己最清楚自己占用了哪些资源,因此最好让任务在删除前自行释放掉这些资源。
方法一:设置清理回调函数,在强制删除时调用
假设有两个任务A和B,A要删除任务B,于是调用任务B的清理回调函数,清理函数负责释放/关闭掉资源,然后就可以删除掉任务B。
方法二:设置删除请求标志,由任务自己决定何时删除
假设有两个任务A和B,A要删除任务B,于是任务A设置删除请求标记,任务B根据需要在合适的时候检查请求标记,若检查到请求标记则自行进行资源清理,如果有清理回调函数,则调用。
方式一:强制删除 | 方式2:请求删除 | |
---|---|---|
删除时机 | 调用时即删除 | 由被删除任务自行决定 |
易用性 | 较差,需要在清理函数中判断删除时需要释放哪些资源 | 较好,处理删除请求时能知道需要清理哪些资源 |
缺点 | 在有些情况下删除无法完成清理操作,例如在调用第三方库时被删除 | 仅仅是设置删除请求,具体何时删除不确定。有可能任务不理会删除处理,或者很长时间之后才处理 |
实现
在task
结构中添加任务删除相关的字段:任务清理函数、清理参数、请求删除标记
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 定义任务结构
typedef struct _t_Task {
taskStack_t *stack; // 任务的栈指针
uint32_t slice; // 时间片
uint32_t delayTicks; // 任务延时计数器,在调用延时函数时每SysTick中断减一
listNode linkNode;
listNode delayNode; // 延时队列结点
uint32_t state; // 任务此时的状态
uint32_t priority; // 任务的优先级
uint32_t suspendCounter; // 挂起计数器
// 任务删除相关:任务清理函数
void (*clean) (void* param);
void* cleanParam;
uint8_t requestDeleteFlag; //请求删除标记
}task_t;
实现相关的几个函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 设置任务的清理回调函数
void taskSetCleanCallFunc (task_t* task, void (*clean)(void* param), void* param) {
task->clean = clean;
task->cleanParam = param;
}
// 强制删除任务
void taskForceDelete (task_t* task) {
uint32_t st = enterCritical();
if (task->state & TASK_STATUS_DELAY) {
taskSched2Undelay(task);
}else if (!(task->state & TASK_STATUS_SUSPEND)) {
taskSched2Unready(task);
}
if (task->clean) {
task->clean(task->cleanParam);
}
if (task == currentTask) {
taskSched();
}
leaveCritical(st);
}
//下面这两个函数的临界区保护不一定需要
// 请求删除任务
void taskRequestDelete(task_t* task){
uint32_t st = enterCritical();
task->requestDeleteFlag = 1;
leaveCritical(st);
}
uint8_t taskIsRequestedDelete(task_t* task) {
uint8_t delete;
uint32_t st = enterCritical();
delete = task->requestDeleteFlag;
leaveCritical(st);
return delete;
}
// 任务删除自己
void taskDeleteSelf(void) {
uint32_t st = enterCritical();
taskSched2Unready(currentTask);
if (currentTask->clean) {
currentTask->clean(currentTask->cleanParam);
}
taskSched();
leaveCritical(st);
}
任务状态的查询
这里要定义一个taskinfo
字段来保存查询的信息,为什么不直接访问task
字段来获取信息呢?因为这样的话一次只能查询到一个信息,如果要一次查询多个信息,那么就需要一个结构来保存查询到的信息。如果执意要通过访问task
结构中的字段来直接获取信息而不用其它结构来保存,那么因为一次只能查询到一个信息,可能会导致前一次查询和后一次查询的逻辑不匹配,例如前一次查询到该任务处于延时态,但是这之后就发生了定时器中断,把这个任务从延时队列中释放了出来,那么紧接着的下一个查询,查询的是剩余延时时间的话,则结果为0,那么就会出现,查询到的状态为延时态,延时时间为0这样显然不匹配的结果,因此需要一次查询多个状态才可以。
实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 任务状态查询结构,用于保存查询的任务状态
typedef struct _taskInfo {
uint32_t state; // 任务此时的状态
uint32_t slice; // 时间片
uint32_t priority; // 任务的优先级
uint32_t suspendCounter; // 挂起计数器
}taskInfo_t;
// 此处性能可以继续优化为下面的版本,避免了创建taskinfo和复制taskinfo的成本
// 但这种方式更符合编程习惯
taskInfo_t getTaskInfo(task_t* task) {
taskInfo_t taskinfo;
uint32_t st = enterCritical();
taskinfo.priority = task->priority;
taskinfo.slice = task->slice;
taskinfo.state = task->state;
taskinfo.suspendCounter = task->suspendCounter;
leaveCritical(st);
return taskinfo;
}
//这个版本的方式相较于上一个函数,开销更小
void getTaskInfo(task_t* task, taskInfo_t* taskinfo) {
uint32_t st = enterCritical();
taskinfo->priority = task->priority;
taskinfo->slice = task->slice;
taskinfo->state = task->state;
taskinfo->suspendCounter = task->suspendCounter;
leaveCritical(st);
}
END
END