任务堆栈的检测方法

描述

使用freeRTOS时,创建的每一个任务都需要分配任务的堆栈空间,这些堆栈空间一般都是使用者根据任务的情况大致分配的。使用者往往不能直接知道分配的任务堆栈空间是否足够任务运行使用,有时候可能会不够,在运行过程中就出现了堆栈溢出,导致程序出现各种各样的奇怪问题,出现问题之后可能一时半会还难以找出来。

这种情况如果能有一种检测手段能够知道任务在运行过程中堆栈的使用情况或者剩余情况,那就可以很好的把握任务堆栈的情况,也可以在一开始就避免堆栈溢出这样的问题发生,将来项目产品上线了也避免了这样的风险存在!

值得开心的是,freeRTOS真的有提供这样的检测堆栈剩余量的功能。下面介绍怎么使用freeRTOS的任务堆栈的剩余量的方法。

1、允许堆栈检测 API 的使用

freeRTOS中堆栈使用剩余量的检测使用的是 uxTaskGetStackHighWaterMark ,使用这个函数需要先将一个宏定义为 1 才能使用堆栈检测功能。

打开 FreeRTOSConfig.h 文件,找到宏

INCLUDE_uxTaskGetStackHighWaterMark 并将其值定为 1,如下:

#define INCLUDE_uxTaskGetStackHighWaterMark     1

这个宏定义为 1 之后再文件 task.c 中就可以看到函数 uxTaskGetStackHighWaterMark 生效了,说明这个函数已经是可以使用的状态了。

2、uxTaskGetStackHighWaterMark 函数的说明

freeRTOS 中任务堆栈的检测函数的函数原型如下:

UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
    {
        TCB_t * pxTCB;
        uint8_t * pucEndOfStack;
        UBaseType_t uxReturn;


        pxTCB = prvGetTCBFromHandle( xTask );


        #if portSTACK_GROWTH < 0
            {
                pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
            }
        #else
            {
                pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
            }
        #endif


        uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack );


        return uxReturn;
    }

函数描述:

函数参数:

xTask:需要检查的堆栈情况的任务句柄。这个句柄在创建任务时就可以知道的。

注意:将 xTask 设置为 NULL 的话检测的就是调用这个函数的任务堆栈情况。

函数返回值:

自创建 xTask 这个任务以来,已存在的最小可用堆栈空间量(以字为单位)。即返回的值是以字为单位的堆栈剩余量(例如,在 32 位机器上,返回值 1 表示任务堆栈中未使用的堆栈还剩余 4 个字节)。如果返回值为零,则该任务可能堆栈已经溢出。如果返回值接近零,则任务接近堆栈溢出。

特别注意:

freeRTOS中还有一个 uxTaskGetStackHighWaterMark2() ,这个是 uxTaskGetStackHighWaterMark() 的另外一个版本,它返回一个用户可定义的类型,主要用在一些 8 位架构上数据类型宽度有限制的MCU中。

3、堆栈剩余量检测的使用方法

3.1、任务自己检测自己的堆栈情况

如果 UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) 的参数 xTask 设置为NULL,则哪个任务调用这个函数检测的就是哪个任务的堆栈情况,如下:

void vTask1( void * pvParameters )
{
    UBaseType_t uxHighWaterMark;

   // 检测任务使用前的堆栈情况
    uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );

    for( ;; )
     {
         ...    // 其他代码
         ...
         ...
         vTaskDelay( 1000 );

         // 检测任务运行之后的堆栈剩余情况
         uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
     }
 }

3.2、使用任务单独检测任务的堆栈情况

可以使用一个任务单独进行项目中的任务堆栈的情况进行检测,如下:

void TaskStackDetect_Task1( void * pvParameters )
{
    UBaseType_t uxHighWaterMark;

    for( ;; )
     {
         uxHighWaterMark = uxTaskGetStackHighWaterMark( 任务句柄1 );
         print(uxHighWaterMark);

         uxHighWaterMark = uxTaskGetStackHighWaterMark( 任务句柄2 );
         print(uxHighWaterMark);

         uxHighWaterMark = uxTaskGetStackHighWaterMark( 任务句柄3 );
         print(uxHighWaterMark);

         ......

         uxHighWaterMark = uxTaskGetStackHighWaterMark( 任务句柄n );
         print(uxHighWaterMark);

         vTaskDelay( 1000 );
     }
 }

3.3、使用软件定时器检测任务堆栈的情况

检测堆栈的剩余情况也可以使用freeRTOS中提供的软件定时器服务,创建一个软件定时器,然后在软件定时器的回调函数里面定时进行检测即可,原理和使用一个任务检测是一样的。如下:

void TaskStackDetect_Callback(TimerHandle_t pxTimer)
{
    UBaseType_t uxHighWaterMark;

    uxHighWaterMark = uxTaskGetStackHighWaterMark( 任务句柄1 );
    print(uxHighWaterMark);

    uxHighWaterMark = uxTaskGetStackHighWaterMark( 任务句柄2 );
    print(uxHighWaterMark);

    uxHighWaterMark = uxTaskGetStackHighWaterMark( 任务句柄3 );
    print(uxHighWaterMark);

         ......

    uxHighWaterMark = uxTaskGetStackHighWaterMark( 任务句柄n );
    print(uxHighWaterMark);
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分