FreeRTOS学习(三)任务管理

1.任务创建

FreeRTOS 提供了多种任务创建的API,这里主要列举了动态创建静态创建

函数 API功能描述
xTaskCreate()动态创建,堆栈由 FreeRTOS 动态分配
xTaskCreateStatic()静态创建,堆栈由用户指定分配

1.1 动态创建

任务的创建一般都采用动态的方式,其API涉及的参数如下

BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,		//任务函数
                        const char * const pcName,		//任务名称
                        const configSTACK_DEPTH_TYPE usStackDepth,	//堆栈大小
                        void * const pvParameters,		//任务函数的参数
                        UBaseType_t uxPriority,			//任务优先级
                        TaskHandle_t * const pxCreatedTask );//任务句柄

这里捡值得注意的地方解释一下

  • 实际申请的堆栈大小usStackDepth 的 4 倍
  • 任务句柄是一个指针,指向申请的任务控制块 TCB_t 的地址

1.2 静态创建

虽然静态创建方式不常用,但是对比认识下区别,加深对任务创建的理解还是有帮助的。

TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,		//任务函数
                                    const char * const pcName,	//任务名称
                                    const uint32_t ulStackDepth,//堆栈大小
                                    void * const pvParameters,	//任务函数的参数 
                                    UBaseType_t uxPriority,		//任务优先级
                                    StackType_t * const puxStackBuffer,	//任务堆栈
                                    StaticTask_t * const pxTaskBuffer )	//任务控制块

一样地,捡重要的说一下

  • 说白了,任务堆栈就是个数组,堆栈大小就是数组的大小
  • 任务控制块就是个结构体,定义一个结构体指针给任务使用即可

先看下代码里上面两点怎么实现的

#define 		TASK1_STK_SIZE			128		//任务堆栈大小			
StackType_t 	Task1Stack[TASK1_STK_SIZE];		//任务堆栈,实际就是uint32_t型的数值
StaticTask_t	Task1TCB;						//任务控制块,结构体类型
...
TaskHandle_t xTaskCreateStatic( TaskHandler,		
                                "Task1",	
                                TASK1_STK_SIZE,
                                NULL,	
                                1,		
                                Task1Stack,	
                                &Task1TCB );

由此也说明了,静态创建所需的两块内存是由用户定义分配的。

1.3 任务创建过程

这一小节从源码的角度深入了解下任务创建的过程中做了哪些事情。
这里以动态创建为例,其创建过程如下
在这里插入图片描述

上面提到一个指针:pxCurrentTCB,比较重要,因为调度器开启的时候就是加载pxCurrentTCB获取第一个任务的TCB
pxCurrentTCB 指向运行态任务的任务控制块,且永远指向当前优先级最高可运行的任务。

pxCurrentTCB 指针更新的场合有两个

  1. 任务创建

在每一次创建任务的时候(不管调度器有没有开启),都会检查新创建任务的优先级是否比当前高,如果是,就把pxCurrentTCB指向这个任务,然后就可以进行任务切换了。

  1. 任务切换

pxCurrentTCB 指向就绪列表中优先级最高的任务。

再来延伸一点,用户创建的任务数不等于实际运行的任务数,因为FreeRTOS还创建了另外两个任务:

  1. 空闲任务
  2. 定时器服务任务,如果开启宏 configUSE_TIMERS

2.任务删除

2.1 函数接口 API

传入参数为任务句柄,如果要删除的是任务自身,可将参数设置为 NULL

void vTaskDelete( TaskHandle_t xTaskToDelete )

另外,如果删除的任务是动态创建的,那么这个任务申请的内存将在空闲任务中被释放。

2.2 任务删除过程

任务删除主要涉及列表内存管理,源码就不在这里分析了,简要过程如下
在这里插入图片描述

3.任务挂起与恢复

3.1 函数接口 API

(1)任务挂起

void vTaskSuspend( TaskHandle_t xTaskToSuspend )

(2)任务恢复

void vTaskResume( TaskHandle_t xTaskToResume )

挂起、恢复与删除类似,都是传入要操作的任务句柄,如果要操作的对象为自身,也可传入参数 NULL

3.2 挂起与恢复过程

任务挂起与恢复的过程可以和删除类比学习,都是对列表进行操作,而且设计到任务切换,但不会像删除任务需要对内存进行处理,简要流程如下:
(1)任务挂起
在这里插入图片描述
(2)任务恢复
在这里插入图片描述

4.任务相关API

除了以上常用的任务管理APIFreeRTOS还提供了一些函数来设置/获取任务属性和状态。

API功能
uxTaskPriorityGet()获取某个任务的优先级
vTaskPrioritySet()设置某个任务的优先级
xTaskGetCurrentTaskHandle()获取当前在运行的任务句柄
xTaskGetHandle()根据任务名字查找任务句柄
eTaskGetState()获取任务状态
uxTaskGetNumberOfTasks()获取当前系统存在的任务数量
vTaskList()以表格形式输出所有任务的状态信息
vTaskGetRunTimeStats()获取每个任务的运行时间

版权声明:本文为la_fe_原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。