在FreeRTOS中,线程的术语又可以被称之为任务,或许这样更加合适,本文将介绍任务的创建/删除,任务参数的使用,以及任务优先级;

1 软实时和硬实时

硬实时系统的任务运行正确性与响应时限是紧密相关的,一旦超过时限将导致严重的后果,比如导弹控制系统、高铁自动驾驶系统等,都是需要严格的响应时限的。

软实时系统中,虽然也存在时限指标,但是如果输出响应超过时限,一般不会造成严重后果,比如Windows桌面任务,DVD播放机的视频播放。

大多数嵌入式系统不仅能满足硬实时要求,也能满足软实时要求。

软实时

  • WindowsLinux系统通常为软实时,当然有补丁可以将内核做成硬实时的系统,不过商用没有这么做的。

硬实时

  • VxWorksuCOSFreeRTOSWinCERT-thread等实时系统;

2 任务概述

2.1 基本写法

FreeRTOS多任务的实时系统,其最基本的运行单元为任务,其表示形式为由C语言函数实现的,该函数原型要求必须返回 void,并且带一个 void 类型指针的参数;具体如下所示;

  1. void ATaskFunc(void *args);

每个任务都是在自己权限范围内的一个小程序。其具有程序入口,通常会运行在一个死循环中,也不会退出,具体如下;

  1. void ATaskFunc(void *args){
  2. while(1){
  3. //TODO
  4. }
  5. }

FreeRTOS 任务不允许以任何方式从实现函数中返回——它们绝不能有一条return语句,也不能执行到函数末尾,如果不再需要,则在任务中调用删除任务的API,具体如下所示;

  1. ```c
  2. void ATaskFunc(void *args){
  3. vTaskDelete( NULL );
  4. }

2.2 TCB

TCB为任务控制块,或者是线程控制块,另外操作系统中还有PCB为进程控制块,主要封装了一个任务在系统调度中所需要的所有资源,FreeRTOSTCB的成员,具体如下所示;

任务状态如下所示;

  1. typedef struct xTASK_STATUS
  2. {
  3. /* The handle of the task to which the rest of the information in the structure relates. */
  4. TaskHandle_t xHandle;
  5. /* A pointer to the task's name.*/
  6. const char *pcTaskName;
  7. /* A number unique to the task. */
  8. UBaseType_t xTaskNumber;
  9. /* The state in which the task existed when the structure was populated. */
  10. eTaskState eCurrentState;
  11. /* The priority at which the task was running (may be inherited) when the structure was populated. */
  12. UBaseType_t uxCurrentPriority;
  13. UBaseType_t uxBasePriority;
  14. uint32_t ulRunTimeCounter;
  15. StackType_t *pxStackBase;
  16. uint16_t usStackHighWaterMark;
  17. } TaskStatus_t;

每一个任务都会拥有一个自己的TCB,具体如下图所示;

  1. typedef struct tskTaskControlBlock
  2. {
  3. volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
  4. #if ( portUSING_MPU_WRAPPERS == 1 )
  5. xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
  6. #endif
  7. ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
  8. ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
  9. UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
  10. StackType_t *pxStack; /*< Points to the start of the stack. */
  11. char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
  12. #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
  13. StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
  14. #endif
  15. #if ( portCRITICAL_NESTING_IN_TCB == 1 )
  16. UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
  17. #endif
  18. #if ( configUSE_TRACE_FACILITY == 1 )
  19. UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
  20. UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
  21. #endif
  22. #if ( configUSE_MUTEXES == 1 )
  23. UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
  24. UBaseType_t uxMutexesHeld;
  25. #endif
  26. #if ( configUSE_APPLICATION_TASK_TAG == 1 )
  27. TaskHookFunction_t pxTaskTag;
  28. #endif
  29. #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
  30. void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
  31. #endif
  32. #if( configGENERATE_RUN_TIME_STATS == 1 )
  33. uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
  34. #endif
  35. #if ( configUSE_NEWLIB_REENTRANT == 1 )
  36. struct _reent xNewLib_reent;
  37. #endif
  38. #if( configUSE_TASK_NOTIFICATIONS == 1 )
  39. volatile uint32_t ulNotifiedValue;
  40. volatile uint8_t ucNotifyState;
  41. #endif
  42. /* See the comments above the definition of
  43. tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
  44. #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
  45. uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
  46. #endif
  47. #if( INCLUDE_xTaskAbortDelay == 1 )
  48. uint8_t ucDelayAborted;
  49. #endif
  50. } tskTCB;

3 任务状态

任务顶层存在两种状态,运行态非运行态

但是非运行的任务状态又可以分为:堵塞状态 / Blocked,挂起状态 / Suspend,就绪状态 / Ready,下面简单做一下介绍;

  • 运行状态 / Running

    运行态的任务完全占用CPU的使用权,如果当前CPU只有一个内核,那么在某个时刻只能运行一个任务,就是所谓的单核单线程;

  • 堵塞状态 / Blocked

    用户可以主动调用vTaskDelay(T)将任务进入堵塞状态,直到任务堵塞时间已经达到T;或者该任务在等待队列,信号量,事件组,通知或信号量事件时,也将处于堵塞状态;处于堵塞状态的任务不再占用CPU,同样也不能直接进入运行状态,而是先进入就绪状态

  • 挂起状态 / Suspend

    任何状态的下的任务都可以通过调用vTaskSuspend函数进入挂起状态,并且无法直接进入运行态,只能通过调用xTaskResume函数进入就绪状态

  • 就绪状态 / Ready

    被抢占的任务将处于就绪状态,挂起的任务被回复的会处于就绪状态,堵塞的任务收到相应事件也会处于就绪状态,如果当前没有更高优先级的任务处于运行,则当前就绪状态的任务进入运行状态

其主要的状态转换关系如下图所示;



FreeRTOS使用一个枚举封装了任务的状态,具体如下所示;

  1. typedef enum
  2. {
  3. eRunning = 0,/* A task is querying the state of itself, so must be running. */
  4. eReady, /* The task being queried is in a read or pending ready list. */
  5. eBlocked, /* The task being queried is in the Blocked state. */
  6. eSuspended, /* The task being queried is in the Suspended state*/
  7. eDeleted, /* The task being queried has been deleted, but its TCB has not yet been freed. */
  8. eInvalid /* Used as an 'invalid state' value. */
  9. } eTaskState;

4 任务优先级

FreeRTOS的最低优先级是0,分配给了空闲任务,空闲任务的优先级使用宏定义tskIDLE_PRIORITY进行表示,最大的优先级为需要用户进行配置;在FreeRTOS.h中可以看到预编译指令,具体如下;

  1. #ifndef configMAX_PRIORITIES
  2. #error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. \
  3. See the Configuration section of the FreeRTOS API documentation for details.
  4. #endif
  5. #if configMAX_PRIORITIES < 1
  6. #error configMAX_PRIORITIES must be defined to be greater than or equal to 1.
  7. #endif

configMAX_PRIORITIES需要用户在FreeRTOSConfig.h进行定义,则任务最大的优先级为configMAX_PRIORITIES - 1

5 相关函数

任务管理的函数声明和一些基本类型都封装在源码tasks.h中;

5.1 创建任务

使用xTaskCreate创建一个任务,具体如下所示;

  1. // Task to be created.
  2. void vTaskCode( void * pvParameters )
  3. {
  4. for( ;; )
  5. {
  6. // Task code goes here.
  7. }
  8. }
  9. // Function that creates a task.
  10. void vOtherFunction( void )
  11. {
  12. static uint8_t ucParameterToPass;
  13. TaskHandle_t xHandle = NULL;
  14. // Create the task, storing the handle. Note that the passed parameter ucParameterToPass
  15. // must exist for the lifetime of the task, so in this case is declared static. If it was just an
  16. // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
  17. // the new task attempts to access it.
  18. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
  19. configASSERT( xHandle );
  20. // Use the handle to delete the task.
  21. if( xHandle != NULL )
  22. {
  23. vTaskDelete( xHandle );
  24. }
  25. }

5.2 函数删除

使用函数vTaskDelete对函数进行删除;

  1. void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;
  2. void vOtherFunction( void )
  3. {
  4. TaskHandle_t xHandle;
  5. // Create the task, storing the handle.
  6. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
  7. // Use the handle to delete the task.
  8. vTaskDelete( xHandle );
  9. }

5.3 堵塞任务

使用vTaskDelay函数可以将任务堵塞一定时间;

  1. void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION;
  2. void vTaskFunction( void * pvParameters )
  3. {
  4. // Block for 500ms.
  5. const TickType_t xDelay = 500 / portTICK_PERIOD_MS;
  6. for( ;; )
  7. {
  8. // Simply toggle the LED every 500ms, blocking between each toggle.
  9. vToggleLED();
  10. vTaskDelay( xDelay );
  11. }
  12. }

5.4 挂起和恢复

使用函数vTaskSuspend可以将函数挂起,通过vTaskResume(xHandle)函数可以将挂起的函数恢复到就绪状态;

  1. void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION;
  2. void vAFunction( void )
  3. {
  4. TaskHandle_t xHandle;
  5. // Create a task, storing the handle.
  6. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
  7. // ...
  8. // Use the handle to suspend the created task.
  9. vTaskSuspend( xHandle );
  10. // ...
  11. // The created task will not run during this period, unless
  12. // another task calls vTaskResume( xHandle ).
  13. //...
  14. // Suspend ourselves.
  15. vTaskSuspend( NULL );
  16. // We cannot get here unless another task calls vTaskResume
  17. // with our handle as the parameter.
  18. }

6 总结

先了解任务之前的状态,先学会使用FreeRTOS的常用接口,后续对于其调度算法和内存管理的算法可以分析和学习一下。


文中难免有错误和纰漏之处,请大佬们不吝赐教

创作不易,如果本文帮到了您;

请帮忙点个赞

【FreeRTOS学习03】小白都能懂的Task Management 任务管理基本概念介绍的更多相关文章

  1. 【FreeRTOS学习04】小白都能懂的 Queue Management 消息队列使用详解

    消息队列作为任务间同步扮演着必不可少的角色: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 相关文章 1 前言 2 xQUEUE 3 相关概念 3 ...

  2. 搭建分布式事务组件 seata 的Server 端和Client 端详解(小白都能看懂)

    一,server 端的存储模式为:Server 端 存 储 模 式 (store-mode) 支 持 三 种 : file: ( 默 认 ) 单 机 模 式 , 全 局 事 务 会 话 信 息 内 存 ...

  3. 【FreeRTOS学习05】深度解剖FreeRTOSConfig.h实现对系统的自定义剪裁

    ROM/RAM太小,因此要对系统进行剪裁: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 相关文章 1 系统的剪裁 2 FreeRTOSConfi ...

  4. 【FreeRTOS学习02】源码结构/数据类型/命名规则总结

    个人不是很喜欢FreeRTOS的编程风格,但是没办法,白嫖人家的东西,只能忍了,这里先简单总结一下: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 ...

  5. JavaScript学习03 JS函数

    JavaScript学习03 JS函数 函数就是包裹在花括号中的代码块,前面使用了关键词function: function functionName() { 这里是要执行的代码 } 函数参数 函数的 ...

  6. Java虚拟机JVM学习03 连接过程:验证、准备、解析

    Java虚拟机JVM学习03 连接过程:验证.准备.解析 类被加载后,就进入连接阶段. 连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去. 连接阶段三个步骤:验证.准备和解析. 类 ...

  7. WEB架构师成长之路-架构师都要懂哪些知识 转

    Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...

  8. WEB架构师成长之路之三-架构师都要懂哪些知识

    Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...

  9. ThinkPhp学习03

    原文:ThinkPhp学习03 一.ThinkPHP 3 的输出      (重点) a.通过 echo 等PHP原生的输出方式在页面中输出 b.通过display方法输出   想分配变量可以使用as ...

随机推荐

  1. JAVA—线程(Thread)

    1.线程的状态有哪些 我记得在操作系统原理的书上有一张具体的图,暂时找不到书... new:新建状态,被创建出来后未启动时的线程状态. runnable:就绪状态,表示可以运行. blocked:阻塞 ...

  2. A Bug's Life POJ - 2492 (种类或带权并查集)

    这个题目的写法有很多,用二分图染色也可以写,思路很好想,这里我们用关于并查集的两种写法来做. 题目大意:输入x,y表示x和y交配,然后判断是否有同性恋. 1 带权并查集: 我们可以用边的权值来表示一种 ...

  3. R - C Looooops POJ - 2115 (exgcd)

    题目大意:很好理解,一个for循环语句,从a开始到b结束,步长是c,模数是pow(2,k) 问,最少循环多少次,才能到达b,如果永远都到不了b,输出FOREVER 题解:其实就是求一个线性方程,cx= ...

  4. C - Ivan the Fool and the Probability Theory---div2

    题目连接:https://codeforces.com/contest/1248/problem/C 思路: 注意上下两排的关系,如果说上面那一排有两个方格连续,那么他相邻的两排必定和他相反,如果说当 ...

  5. Ubuntu搭建Redis 集群

    1.源码编译 查看需要下载版本:http://download.redis.io/releases/ 本人保存路径:/usr/local/soft/ wget http://download.redi ...

  6. .NET 4 实践 - 使用dynamic和MEF实现轻量级的AOP组件 (4)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/23/1783394.html 借花献佛 前面我们介绍了构成DynamicAspect绝大部分的类, ...

  7. JasperReports入门教程(一):快速入门

    JasperReports入门教程(一):快速入门 背景 现在公司的项目需要实现一个可以配置的报表,以便快速的适应客户的需求变化.后来在网上查资料发现可以使用JasperReports + Jaspe ...

  8. 可以用 Python 编程语言做哪些神奇好玩的事情?除了生孩子不能,其他全都行!

    坦克大战 源自于一个用Python写各种小游戏的github合集,star数1k.除了坦克大战外,还包含滑雪者.皮卡丘GOGO.贪吃蛇.推箱子.拼图等游戏. 图片转铅笔画 帮助你快速生成属于自己的铅笔 ...

  9. redis的5种数据类型

    卸载服务:redis-server --service-uninstall 开启服务:redis-server --service-start 停止服务:redis-server --service- ...

  10. 【集群实战】共享存储实时备份(解决nfs共享存储的单点问题)

    1. nfs存储的单点问题 如果nfs服务器宕机了,则所有的nfs客户机都会受到影响.一旦宕机,会丢失部分用户的数据.为了解决单点问题,需要实现共享存储的实时备份,即:将nfs服务端共享目录下的数据实 ...