RTOS任务堆栈分配多大才合适?

原文链接:RTOS任务堆栈分配多大才合适?

之前有读者问了这样一个问题:我有个任务中的代码量很多,是不是这个任务的堆栈需要分配很大才行?

下面就围绕任务代码量,以及堆栈进行描述相关内容。

1.RTOS任务堆栈分配

市面上很多RTOS的任务都是需要提前分配堆栈大小,也就是在创建任务的时候分配好堆栈的大小。

比如uCOS创建一个检测(Check)任务:


// 任务优先级
#define TASK_CHECK_PRIO                        6

// 任务堆栈大小
#define TASK_CHECK_STK_SIZE                    128

// 堆栈
OS_STK TaskCheckStk[TASK_CHECK_STK_SIZE];

// 创建任务 - 信号检测
OSTaskCreateExt((void (*)(void *)) AppTaskCheck,
                (void           *) 0,
                (OS_STK         *)&TaskCheckStk[TASK_CHECK_STK_SIZE-1],
                (INT8U           ) TASK_CHECK_PRIO,
                (INT16U          ) TASK_CHECK_PRIO,
                (OS_STK         *)&TaskCheckStk[0],
                (INT32U          ) TASK_CHECK_STK_SIZE,
                (void           *) 0,
                (INT16U          )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));

// 任务应用实现
void AppTaskCheck(void *p_arg)
{
  // 代码···

  (void)p_arg;

  for(;;)
  {
    // 代码···
  }
}

FreeRRTOS创建一个任务类似,也是在创建时分配堆栈大小:

#define TASK_CHECK_PRIO                        6
#define TASK_CHECK_STK_SIZE                    128

BaseType_t xReturn;

xReturn = xTaskCreate(AppTaskCheck, "AppTaskCheck", TASK_CHECK_STK_SIZE, NULL, TASK_CHECK_PRIO, NULL);

除了堆栈,其实还有像消息队列、消息邮箱等也是需要提前分配堆栈。

比如FreeRTOS创建CLI消息队列:


#define CLI_QUEUE_NUM             256                      //CLI接收队列数
#define CLI_PACKAGE_LEN           2                        //CLI数据包长度

QueueHandle_t xCLIRcvQueue = NULL;

/* 创建队列 */
if(xCLIRcvQueue == NULL)
{
  xCLIRcvQueue = xQueueCreate(CLI_QUEUE_NUM, CLI_PACKAGE_LEN);
}

这就是创建任务(或队列)的分配堆栈,至于具体分配多少,与你实际情况有关,下面章节我会描述。

2.任务代码量

一个任务的代码量,就是你任务中调用的那些代码。

比如上面例子中的代码:


// 任务应用实现
void AppTaskCheck(void *p_arg)
{
  // 代码···

  (void)p_arg;

  for(;;)
  {
    // 代码···
  }
}

这里可能写了几千行代码,或者调用了上百个函数,每个函数里面都有不少代码。

这样下来,这一个任务的代码量就很大了。

3.任务代码量和堆栈大小有关系吗?

很多人就存在一个疑惑:任务挂起,要在堆栈中临时保存任务,如果这个任务的代码量很大,是不需要很大堆栈空间才行?

答案:不一定需要很大堆栈空间,任务代码量和堆栈也没有直接关系。

可能很多初学者存在这么一个误区:保存一个任务,就是把这个任务所有代码都保存起来(在堆栈中)。

堆栈主要保存是这个任务自身的变量(控制块),还有临时变量等这些关键变量信息,而并非要保存所有代码。

4.堆栈分配多大才合适?

任务堆栈大小,主要取决于你任务中【临时变量】的多少。

注意:临时变量包含你代码中所有嵌套函数中的临时变量。

对于RAM资源相对较大的处理器,你可以尽量分配多一点堆栈资源。

但是,很多时候,我们的RAM资源都是相对比较紧张的。这个时候,就需要你综合平衡。

比如静态局部变量:


void AppTaskCheck(void *p_arg)
{
  static uint8_t aaa;  //静态局部变量

  (void)p_arg;

  for(;;)
  {
    // 代码···
  }
}

这里的aaa变量就不会占用该任务的堆栈空间,但是它会占用全局变量(RAM)空间。

用静态局部变量,还是临时变量,要牵涉到你项目具体情况,比如:RAM资源、代码运行效率等。(临时变量还会有一个数据拷贝过程)

所以,该如何分配堆栈,该用静态还是临时变量,需要综合考虑你项目的情况而定。

版权归原作者所有,如有侵权,请联系删除。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RTOS(Real-Time Operating System)任务调度是实时操作系统中非常重要的一部分,它负责协调多个任务的执行,使得它们能够按照一定的优先级、时间片或其他算法在 CPU 上运行。RTOS 任务调度的实现方式可以分为两种:抢占式和非抢占式。 1. 抢占式任务调度 抢占式任务调度是指当一个优先级更高的任务就绪时,它可以抢占当前正在运行的任务并立即执行。在抢占式任务调度中,每个任务都有一个优先级,调度器会根据任务的优先级来决定其执行顺序。当一个高优先级任务就绪时,调度器会立即抢占当前正在执行的任务并执行高优先级任务。抢占式任务调度实现的关键在于中断处理,当一个中断发生时,调度器会暂停当前正在执行的任务并执行中断服务程序,然后在中断服务程序执行完毕后恢复原来的任务继续执行。 2. 非抢占式任务调度 非抢占式任务调度是指任务只有在自己执行完毕或主动放弃 CPU 时才会被其他任务抢占。在非抢占式任务调度中,每个任务也有一个优先级,但是任务的执行顺序只能由任务本身控制。当一个任务执行完毕或主动放弃 CPU 时,调度器会根据任务的优先级来选择下一个任务执行。非抢占式任务调度实现的关键在于任务的协作,每个任务需要在执行过程中主动让出 CPU,以便其他任务得到执行的机会。 无论是抢占式还是非抢占式任务调度,都涉及到任务的上下文切换,即保存当前任务的上下文,以便在任务再次执行时恢复其状态。上下文切换需要保存任务的 CPU 寄存器、堆栈指针等信息,并修改当前任务的状态(如就绪、阻塞等),然后切换到下一个任务的上下文。任务的上下文切换是一个比较耗时的操作,因此在任务调度的实现中需要尽量减少上下文切换的次数,提高任务的执行效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值