目录
1 任务相关概念
1.1 任务状态
任务通常分为分为四个状态,分别是:
(1)就绪——任务在就绪列表
(2)运行——任务正在运行
(3)阻塞——任务不在就绪列表,也没在执行,等待着被事件触发
(4)退出——任务运行结束,等待系统回收资源
- 任务运行结束时或者阻塞的任务调用删除接口时,任务会进入退出态。
- 任务调度的机制主要围绕就绪、运行、阻塞进行变化。
1.2 任务控制块TCB
TCB包含了任务上下文栈指针(stack pointer)、任务状态、任务优先级、任务ID、任务名、任务栈大小等信息。TCB可以反映出每个任务运行情况。
1.3 任务入口函数
任务得到调度之后将执行的函数。(能控制任务状态的API任务接口)
1.4 任务优先级
表示任务执行的优先顺序,在此处数字越大优先级越高。不修改内核代码的情况下为0~31共32的优先级。
1.5 任务ID
任务创建时通过参数返回给用户,作为任务的一个非常重要的标识。
1.6 任务栈
每一个任务都拥有一个独立的栈空间,称为任务栈。
1.7 任务上下文
任务在运行过程中使用到的一些资源,如寄存器等,称为任务上下文。LiteOS在任务挂起的时候会将本任务的任务上下文信息,保存在自己的任务栈里面,以便任务恢复后,从栈空间中恢复挂起时的上下文信息,从而继续执行被挂起时被打断的代码。
1.8 任务切换
任务切换包含获取就绪列表中最高优先级任务、切出任务上下文保存、切入任务上下文恢复等动作。
2 任务调度
任务调度是安排任务执行的行为,实际上是依赖于任务状态的切换(不是任务切换,是状态切换)。
任务状态的切换图如图2.1所示。
各个任务状态的切换中,需要注意的有以下几点:
- 阻塞态要切换到运行态,需要先切换成就绪态,并在优先级运行的前提下等待系统调度,进入运行态。
- 发生任务切换时,就绪列表中最高优先级的任务被执行,从而进入运行态,但此刻该任务依旧在就绪列表中。
- 任务运行结束,内核自动将此任务删除,此时由运行态变为退出态。
- 阻塞的任务调用删除接口,任务状态由阻塞态变为退出态。
- 任务运行因挂起、读信号量等待等,在就绪列表中被删除进入阻塞。
3 任务管理
实现任务的管理实际,在适当的情况下运行所需要的任务,这就得依赖任务调度机制。
实现任务管理中需要用到cmsis_os2的API任务接口,常用的API任务接口如表3.1所示
接口名 | 功能 |
---|---|
osThreadNew | 创建任务 |
osThreadTerminate | 删除任务 |
osThreadSuspend | 任务挂起 |
osThreadResume | 任务恢复 |
此处围绕任务创建的参数进行展开说明:
osThreadNew(osThreadFunc_t func, void * argument, const osThreadAttr_t * attr)
func:任务函数
argument:作为启动参数传递给任务函数的指针
attr:任务入口函数的参数列表,此处就传递给osThreadNew()任务接口。
任务创建函数的返回值即为任务ID。
4 实战案例
案例实现目标:创建两个任务,分别以不同的时间间隔打印对应信息,穿插任务状态切换的过程。
主要使用任务创建函数接口。
示例代码一:任务函数
void threadHi(void)
{
printf("enter threadHi\r\n");
osDelay(1);
printf("threadHi delay done\r\n");
osThreadSuspend(threadHiID);//任务一挂起
printf("threadHi osThreadResume success\r\n");
osThreadTerminate(threadHiID);//删除任务一
}
void threadLo(void)
{
for(int i = 0; i < 10; i++)
{
printf("enter threadLo\r\n");
}
printf("threadHi osThreadSuspend success\r\n");
osThreadResume(threadHiID);//任务一恢复
osThreadTerminate(threadLoID);//任务二删除
}
示例代码二:创建任务
osThreadId_t threadHiID ;//任务一ID
osThreadId_t threadLoID ;//任务二ID
/*****任务创建*****/
static void Thread_example(void)
{
osThreadAttr_t attr;
attr.name = "threadHi";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 25;
threadHiID = osThreadNew((osThreadFunc_t)threadHi, NULL, &attr);
if ( threadHiID == NULL)
{
printf("Falied to create threadHi!\n");
}
attr.name = "threadLo";
attr.priority = 24;
threadLoID = osThreadNew((osThreadFunc_t)threadLo, NULL, &attr);
if (threadLoID == NULL)
{
printf("Falied to create threadLo!\n");
}
}
SYS_RUN(Thread_example);//自启动
最后在业务gn文件和模块gn文件上进行相应修改,编译烧写到开发板中。
5 案例分析
案例一开始设置了任务的一些相关参数,用以进行任务创建。通过任务ID判断任务创建的情况,根据创建成功与否的情况打印相应的信息。此次分析主要分析任务调度的情况。
因为任务一的优先级为25,高于任务二24,所以任务创建时两个任务处于就绪态。
具体流程如图5.1所示
初次学习,描述有误欢迎评论区指出。