Freertos学习04-Task状态
一、前言
FreeRTOS是一个流行的实时操作系统,它支持多任务处理。在FreeRTOS中,任务有不同的状态,这些状态反映了任务在系统中的行为。
二、状态特点
任务可以存在于以下状态中:
-
运行
当任务实际执行时,它被称为处于运行状态。 任务当前正在使用处理器。 如果运行 RTOS 的处理器只有一个内核, 那么在任何给定时间内都只能有一个任务处于运行状态。 -
准备就绪
准备就绪任务指那些能够执行(它们不处于阻塞或挂起状态), 但目前没有执行的任务, 因为同等或更高优先级的不同任务已经处于运行状态。 -
阻塞
如果任务当前正在等待时间或外部事件,则该任务被认为处于阻塞状态。 例如,如果一个任务调用vTaskDelay(),它将被阻塞(被置于阻塞状态), 直到延迟结束-一个时间事件。 任务也可以通过阻塞来等待队列、信号量、事件组、通知或信号量 事件。 处于阻塞状态的任务通常有一个"超时"期, 超时后任务将被超时,并被解除阻塞, 即使该任务所等待的事件没有发生。
“阻塞”状态下的任务不使用任何处理时间,不能 被选择进入运行状态。
- 挂起
与“阻塞”状态下的任务一样, “挂起”状态下的任务不能 被选择进入运行状态,但处于挂起状态的任务 没有超时。 相反,任务只有在分别通过 vTaskSuspend() 和 xTaskResume() API 调用明确命令时 才会进入或退出挂起状态。
以上几种状态中需要注意挂起态和阻塞态,函数可以通过调用vTaskDelay()函数来进入阻塞态,挂起态则通过vTaskSuspend()进入挂起态
三、实例测试
1.相关函数
1)挂起函数vTaskSuspend()
,这个函数可以将任务从就绪、运行、以及阻塞态置入挂起态,输入参数为任务的句柄,将函数写在任务函数的内部可以将自己挂起,此时输入参数无须句柄,为NULL。
2)挂起所有任务函数vTaskSuspendAll()
,这个函数的工作原理是系统维护一个全局变量uxSchedulerSuspended的计数值,对于FreeRTOS来说,task的切换是在中断中发生的,如果中断进来,中断中会对uxSchedulerSuspended这个变量的值进行判断,从而决定是否需要进行Task切换。当其大于0的时候禁止调度,等于0的时候表示允许调度。
如果调度器挂起话,当前正在执行的Task会一直继续执行,内核不再调度(意味着当前任务不会被切换出去),直到该任务调用了xTaskResumeAll()函数。
注意在使用vTaskSuspendAll()
挂起其余任务区间,不允许调用其他FreeRTOS API 函数。
3)恢复函数vTaskResume()
,挂起函数相对,恢复函数可以将处于挂起状态的函数恢复至就绪态,注意只能是就绪态。使用时只需要传入句柄即可。
4)恢复所有函数xTaskResumeAll()
,可与vTaskSuspendAll()
配合使用,将所有函数的挂起态解除。
2.代码测试
测试1:该例子在任务创建之后先将task1挂起,经短暂延迟恢复,所以可以观察到有一段只有task2输出,task1无输出:
#include <stdio.h> #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "sdkconfig.h" void mytask1(void *pvParam) { while (1) { printf("111-task1 \n"); vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时 } } void mytask2(void *pvParam) { while (1) { printf("222-task2 \n"); vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时 } } void app_main(void) { TaskHandle_t xHandle = NULL; // 任务句柄 xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, &xHandle); // 传入参数 xTaskCreate(mytask2, "mytask2", 1024, NULL, 2, NULL); // 传入参数 vTaskDelay(2000 / portTICK_PERIOD_MS); // 延时 vTaskSuspend(xHandle); // 挂起 vTaskDelay(2000 / portTICK_PERIOD_MS); // 延时 vTaskResume(xHandle); // 恢复 }
测试2:测试vTaskSuspendAll()
与xTaskResumeAll()
,有时我们需要保证某个任务运行期间不被打扰,例如对都某时间点的各传感器数据进行采样,因为要保证传感器数据尽量在同一时刻采集,所以此时我们可以停止其他任务调度,等待采集结束后再恢复。
#include <stdio.h> #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "sdkconfig.h" void mytask1(void *pvParam) { printf("task1-begin \n"); vTaskSuspendAll(); // 挂起所有任务 for (int i = 0; i < 9999; i++) { for (int j = 0; j < 9999; j++) { ; // 模拟不可中断任务 } } xTaskResumeAll(); // 恢复所有任务 printf("task1-over \n"); vTaskDelete(NULL); } void mytask2(void *pvParam) { while (1) { printf("222-task2 \n"); vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时 } } void app_main(void) { TaskHandle_t xHandle = NULL; // 任务句柄 xTaskCreate(mytask1, "mytask1", 2048, NULL, 1, &xHandle); // 传入参数 xTaskCreate(mytask2, "mytask2", 2048, NULL, 2, NULL); // 传入参数 }
测试结果:符合预期。
THE END!
本文作者:seekwhale13
本文链接:https://www.cnblogs.com/seekwhale13/p/17506877.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步