FreeRTOS—TCB_t结构体及重要变量说明

2023-05-16

1.TCB_T

TCB_t的全称为Task Control Block,也就是任务控制块。

typedef struct tskTaskControlBlock             
{
        //栈顶指针,中断或任务切换时,会对任务压栈
        volatile StackType_t    *pxTopOfStack;    

        // 启用MPU的情况下设置
        #if ( portUSING_MPU_WRAPPERS == 1 )
            /* 设置任务访问的内存权限 */
            xMPU_SETTINGS    xMPUSettings;        
        #endif

        // 表示任务状态,不同的状态会挂接在不同的状态链表下
        ListItem_t            xStateListItem;    
        // 事件链表项,会挂接到不同事件链表下
        ListItem_t            xEventListItem;        
        // 任务优先级,数值越大优先级越高
        UBaseType_t            uxPriority;            
        // 指向堆栈起始位置,这只是单纯的一个分配空间的地址,可以用来检测堆栈是否溢出
        StackType_t            *pxStack;            
        // 任务名
        char                pcTaskName[ configMAX_TASK_NAME_LEN ];

        /* 对于向上生长的栈,用于指明栈的上边界,用于判断是否溢出 */
        #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
            StackType_t        *pxEndOfStack;        
        #endif

        // 记录临界段的嵌套层数
        #if ( portCRITICAL_NESTING_IN_TCB == 1 )
            UBaseType_t        uxCriticalNesting;    
        #endif

        // 跟踪调试用的变量
        #if ( configUSE_TRACE_FACILITY == 1 )
             /* 用于调试,表示本任务是第几个创建,每创建一个任务,系统有一个全局变量加1*/
            UBaseType_t        uxTCBNumber; 
            /* 调试用,用户通过API函数vTaskSetTaskNumber()来设置,数值由函数参数指定 */
            UBaseType_t        uxTaskNumber;        
        #endif

        /* 如果使用任务互斥量信号 */
        #if ( configUSE_MUTEXES == 1 )
           /* 优先级提升前,保存原优先级,优先级反转时用*/
            UBaseType_t        uxBasePriority;   
           /* 任务获取的互斥信号量个数,为0*/
            UBaseType_t        uxMutexesHeld;
        #endif

        // 任务的一个标签值,可以由用户自定义它的意义,例如可以传入一个函数指针可以用来做Hook    函数调用
        #if ( configUSE_APPLICATION_TASK_TAG == 1 )
            TaskHookFunction_t pxTaskTag;
        #endif

        // 任务的线程本地存储指针,可以理解为这个任务私有的存储空间
        #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
            void            *pvThreadLocalStoragePointers[     configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
        #endif

        // 运行时间变量
        #if( configGENERATE_RUN_TIME_STATS == 1 )
            uint32_t        ulRunTimeCounter;    
        #endif

        // 支持NEWLIB的一个变量
        #if ( configUSE_NEWLIB_REENTRANT == 1 )
            struct    _reent xNewLib_reent;
        #endif

        // 任务通知功能需要用到的变量
        #if( configUSE_TASK_NOTIFICATIONS == 1 )
            // 任务通知的值 
            volatile uint32_t ulNotifiedValue;
            // 任务通知的状态
            volatile uint8_t ucNotifyState;
        #endif

        // 用来标记这个任务的栈是不是静态分配的
        #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) 
            uint8_t    ucStaticallyAllocated;         
        #endif

        // 延时是否被打断
        #if( INCLUDE_xTaskAbortDelay == 1 )
            uint8_t ucDelayAborted;
        #endif

        // 错误标识
        #if( configUSE_POSIX_ERRNO == 1 )
            int iTaskErrno;
        #endif
    } tskTCB;
    typedef tskTCB TCB_t;///*上面维护旧的tskTCB名称,然后定义为下面的新TCB_t名称

栈的生长方式可以分为两种,一种是向下生长,一种是向上生长,FreeRTOS中用portSTACK_GROWTH来区分这两种生长方式,portSTACK_GROWTH大于0为向上生长,小于零为向下生长。两种生长方式的区别可以简单概括如下:

  • 向上生长:入栈时栈顶指针增加,出栈时栈顶指针减小。

  • 向下生长:入栈时栈顶指针减小,出栈时栈顶指针增加。

 以下为两种生长方式的示意图:

有了上图栈的生长方式为什么会影响成员变量的个数很好理解了,pxStack是指向栈内存分配的起始地址(低地址),pxEndOfStack是指向栈的尾部的,当栈是向下生长时,pxStack和pxEndOfStack值是一致的,再定义pxEndOfStack浪费了内存,而栈是向上生长时pxStack与pxEndOfStack的值不一致,如果想知道栈的结束地址,必须要定义一个变量pxEndOfStack来存储,以用于后续的栈溢出检测等操作。

2.状态链表

FreeRTOS中的任务一共有四种状态分别是运行状态(Running State),就绪状态(Ready State),阻塞状态(Blocked State),挂起状态(Suspended State),其中:

运行状态:正在执行的任务。

就绪状态:等待获得执行权的任务。

阻塞状态:直到某些条件达成才会重新进入就绪态等待获得执行权,否则不会执行的任务。

挂起状态:除非被主动恢复,否则永远不会执行。

 四种任务状态的转换关系如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6fATzBg-1572180165350)(pic/task/full-task-state-machine.png)]

这四种链表分别对应着pxCurrentTCB,pxReadyTasksLists,pxDelayedTaskList,xSuspendedTaskList这四个变量。除运行状态外,任务处于其它状态时,都是通过将任务TCB中的xStateListItem挂到相应的链表下来表示的。

3.与任务相关变量

3.1.pxCurrentTCB

PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;

当前运行任务只可能有一个,则pxCurrentTCB只是单个TCB_t指针,始终指向当前运行的任务。

3.2.pxReadyTasksLists

PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];

pxReadyTasksLists不是单个链表,它是configMAX_PRIORITIES个链表组成的链表数组。链表数组中的每一个成员都是由处于就绪态而又有着相同任务优先级的任务组成的的链表。与之相关的还有一个变量uxTopReadyPriority。uxTopReadyPriority的定义如下:

PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;

uxTopReadyPriority存储的是有任务挂接的最高优先级。pxReadyTasksLists、pxCurrentTCB和uxTopReadyPriority三者之间的关系可由以下的图来表示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5dypN2g9-1572180165351)(pic/task/ready-list.png)]

 当使用时间片时,pxCurrentTCB会在有任务挂接的最高优先级链表中遍历,以实现它们对处理器资源的分时共享,这些具体过程会在后面进行详细分析。

3.3. pxDelayedTaskList

延时链表的作用不仅是用来处理任务的延时,任务的阻塞也是由它进行实现的(至少目前分析的源码看是这样的)。由于pxDelayedTaskList要处理和时间相关的信息,因此需要考虑到系统的systick溢出的处理。为了解决这一繁琐的问题,FreeRTOS设计了两个延时链表和两个延时链表指针来处理溢出问题,它们的定义如下:

PRIVILEGED_DATA static List_t xDelayedTaskList1;                        
PRIVILEGED_DATA static List_t xDelayedTaskList2;                        
PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList;                
PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList;

其中pxDelayedTaskList指向当前工作的延时任务链表,而pxOverflowDelayedTaskList指向溢出后的链表,xDelayedTaskList1和xDelayedTaskList2是两个实际链表,其中任务的排列顺序是按退出阻塞时间排序的,也就是链表的第一个成员任务是将最早退出阻塞,而最后一个成员任务是最后退出阻塞的。当系统的systick溢出时,pxDelayedTaskList和pxOverflowDelayedTaskList指向的链表地址也会随之交换一次,实现对溢出的处理。对于溢出的处理会在"任务的延时阻塞的实现"进行分析。以下是四个变量之间的关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tKVYzNaA-1572180165352)(pic/task/delay-list.png)]{width="0.9\linewidth"}

与延时任务链表变量为xNextTaskUnblockTime。其定义如下

PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U;

xNextTaskUnblockTime存储的是下一个任务进行解除阻塞操作的时间,用来判断在何时进行解除阻塞操作。

3.4. xSuspendedTaskList

PRIVILEGED_DATA static List_t xSuspendedTaskList;

其是一个普通的链表,下面挂接的是处于挂起状态的任务。

4.任务调度器操作相关变量

4.1. xSchedulerRunning

PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;

该变量表示任务调度器是否已经运行(挂起的任务调度器也算在运行状态)。

4.2. uxSchedulerSuspended

PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE

uxSchedulerSuspended的作用是记录任务调度器被挂起的次数,当这个变量为0(dFALSE)时,任务调度器不被挂起,任务调度正常执行,当这个变量大于0时代表任务调度器被挂起的次数。如果执行挂起任务调度器操作该变量值会增加,如果执行恢复任务调度器操作,该变量值会减一,直到它为0时才会真正的执行实际的调度器恢复操作,这样可以有效的提高执行效率,这点在后面关于任务调度器的操作上会进一步探讨。

4.3. uxPendedTicks

PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;

任务调度器在被挂起期间,系统的时间,仍然是需要增加的。挂起期间漏掉的systick数目便会被存储在这个变量中,以用于恢复调度器时补上漏掉的systick。

4.4. xPendingReadyList

PRIVILEGED_DATA static List_t xPendingReadyList;

这个链表中挂接的是在任务调度器挂起期间解除阻塞条件得到满足的阻塞任务,在任务调度器恢复工作后,这些任务会被移动到就绪链表组中,变为就绪状态。

5.任务删除相关变量

5.1. xTasksWaitingTermination

PRIVILEGED_DATA static List_t xTasksWaitingTermination;

当任务自己删除自己时,其是不能立刻自己释放自己所占用的内存等资源的,其需要将自己挂接到xTasksWaitingTermination这个链表下,然后让IdleTask来回收其所占用的资源。

5.2. uxDeletedTasksWaitingCleanUp

PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType

uxDeletedTasksWaitingCleanUp记录了等待IdleTask处理的自己删除自己的任务的数目。

5.3. xIdleTaskHandle

PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle    = NULL;

TaskHandle_t本质上是指向任务TCB的指针,IdleTask是任务调度器在启动时便自动创建的空闲任务,用于回收内存等操作,这个任务句柄指向IdleTask。

6.系统信息相关

6.1. xTickCount

PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL

存储systick的值,用来给系统提供时间信息。

6.2. xNumOfOverflows

PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows     = ( BaseType_t ) 0;

这个值保存了xTickCount溢出的次数。

6.3. uxTaskNumber

PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;

每创建一个任务,这个值便会增加一次,为每个任务生成一个唯一的序号,供调试工具使用。注意与uxCurrentNumberOfTasks区分。

6.4. uxCurrentNumberOfTasks

PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks     = ( UBaseType_t ) 

存储当前任务的数目。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS—TCB_t结构体及重要变量说明 的相关文章

  • python数据结构算法DAY3| 堆排序

    目录 前言 1 什么是堆排序 xff1f 堆的向下调整性质 2 堆排序思路 3 堆排序代码 python中堆排序的内置模块 4 堆排序时间复杂度 5 堆排序解决topk问题 前言 堆排序是基于完全二叉树 xff0c 堆是一种特殊的完全二叉树
  • Apache IoTDB’s UDF源码分析(1)

    目录 前言 命令行注册UDF函数 Create Function xxx as 34 全限定类名 34 语法分析 生成物理计划 执行物理计划进行函数注册 Select带有UDF函数的查询 前言 继上个月开始了Apache IoTDB的源码贡
  • 新手入门贡献Apache IoTDB

    名词解释 Issue 开源社区的一个任务的统称 xff0c 通常会有一个Issue 列表 xff0c 用于表示各种任务 xff0c 比如功能Issue Bug Issue Improvement Issue等 PR Pull Request
  • Apache IoTDB介绍

    什么是时序数据库 时序数据库 为万物互联插上一双翅膀 有态度的HBase Spark BigData 总体介绍 Apache IoTDB 始于清华大学软件学院 xff0c 是一款时序数据库 主要使用场景是在物联网相关行业 xff0c 如 x
  • 以回溯的思想求解0-1背包问题

    以回溯法的思想求解0 1背包问题 目录 介绍 求解 介绍 0 1背包问题 问题描述 给定n种物品和一背包 物品i的重量是wi xff0c 其价值为pi xff0c 背包的容量为C 问应如何选择装入背包的物品 xff0c 使得装入背包中物品的
  • Qt中QMessageBox中的几种常见用法归纳

    Qt中QMessageBox中的几种常见用法归纳 最简单的弹出一个提示框 QMessageBox question this 34 Title 34 34 Content 34 QMessageBox warning this 34 Tit
  • Java Web学习里遇到一些问题

    Java Web学习里遇到一些问题 在使用Java Bean技术时 xff0c 新建一个Bean类时 xff0c 直接放到src里 xff0c 在Intellij IDEA里会解析不了 xff0c 要在src里建个包将其放到包里 xff0c
  • python里类声明里一个比较坑的错误

    python里类声明里一个比较坑的错误 正确的 import pygame from pygame sprite import Sprite class Alien Sprite 34 34 34 初始化外星人并设置其起始位置 34 34
  • MySQL存储时间出现不一致的问题

    用Java在获取了系统时间后 xff0c 存入MySQL数据库时 xff0c 当时间的类型为datetime或Timestamp时发现数据库的存储与本地时间不一致 很大原因是 xff0c MySQL设置的时区与你本地时区不一致造成的 xff
  • 在运用Putty连接远程服务器时遇到的坑:server unexpectedly closed network

    在运用Putty连接远程服务器时遇到的坑 xff1a server unexpectedly closed network 如果是在Putty需输入那个密码的 xff0c 那个密码是默认不显示 xff0c 你输完后一定要记得敲回车 xff0
  • Java中的==与equals()的区别(1)

    Java中的 61 61 与equals 的区别 xff08 1 xff09 package study public class Note1 public static void main String args TODO Auto ge
  • cookie,session和token详解和区别

    目录 前言 1 cookie和session是为了解决什么问题产生的 xff1f 2 什么是会话技术 xff1f 3 cookie详解 Cookie的表示 Cookie的组成 Cookie的HTTP传输 Cookie的生命周期 cookie
  • 读 Thinking in Java 笔记(1)

    读 Thinking in Java 笔记 xff08 1 xff09 请看下面这个例子 xff08 结构简单 xff0c 但各种创建可能会有点晕 xff0c 你可以通过它推出正确的打印顺序 xff0c 就基本过关了 xff0c 这里还包含
  • JAVA泛型的学习(1)

    JAVA泛型的学习 xff08 1 1 什么是泛型 xff1f 泛型 xff08 generic xff09 可以参数化类型 xff0c 使我们在定义带泛型类型的类或方法时 xff0c 随后编译器会用具体的类型来替换它 个人感觉与C 43
  • JAVA泛型的学习(2)

    JAVA泛型的学习 xff08 2 xff09 1 受限泛型类型 lt E extends xxx gt 将E指定为xxx的泛型子类型 非受限泛型 lt E gt 等同于 lt E extends Object gt public stat
  • JAVA泛型的学习(3)

    JAVA泛型的学习 xff08 3 xff09 1 消除泛型 泛型是使用一种成为类型消除的方法实现的 编译器使用泛型类型信息来编译代码 xff0c 但是随后会消除它 因此泛型信息在运行时是不可用的 泛型存在于编译时 xff0c 一旦编译器确
  • 在进行Web开发时需注意的一个坑(明明改了代码,就是没变化)

    在进行Web开发时需注意的一个坑 在进行web开发时有时候你会发现这样一种奇怪的现象 xff1a 就是你明明改了代码了 xff0c 反映到浏览器上就是一点变化也没有 xff0c 这时候有可能是代码本身有问题但还要留意就是浏览器有个缓存 xf
  • 整理牛人看文献的方法

    总结一 1 xff08 从phd到现在工作半年 xff0c 发了12篇paper xff0c 7篇firstauthor xff09 我现在每天还保持读至少 2 3 篇的文献的习惯 读文献有不同的读法 但最重要的自己总结概括这篇文献到底说了
  • npm安装包,出现:Failed to parse json, Trailing comma in object at 25:3

    原因就是不能够解析json文件 xff0c 可以查看一下 xff0c json文件中的语法是否有误 xff0c 比如双引号 xff0c 逗号等
  • CSS清除Google浏览器默认样式

    span class token selector html body div span applet object iframe h1 h2 h3 h4 h5 h6 p blockquote pre a abbr acronym addr

随机推荐