堆栈作用的就是用来保存局部变量,从本质上讲也就是将CPU寄存器的值保存到RAM中。在uCOS中,每一个任务都有一个独立的任务堆栈。为了深入理解任务堆栈的作用,不妨分析任务从“出生”到“消亡”的整个过程,具体就是分析任务的建立,运行,挂起几种状态中任务堆栈的变化情况。现在假设系统运行着一个由用户创建的用以完成打印工作的任务TPrint。TPrint最初通过OSTaskCreate()函数创建,在该函数中与任务堆栈有关的第一段代码是大家比较熟悉的函数OSTaskStkInit(),这个函数是在uCOS移植过程中必须实现的,其作用是“初始化堆栈”,其实就是预先在RAM中的一块区域中把任务将来运行开始时CPU寄存器应处的状态(正确值)准备好,之后,任务第一次被内核调度器调度运行时,将这些准备好的数据(寄存器的值)推到CPU的寄存器中,如果数据设计的合理,CPU便会按照我们预先设计好的思路运行。所以,“初始化堆栈”实际上是做了一个“未雨绸缪”的工作。这个过程中有两点是必须慎重考虑的,一是PC该如何定位,二是CPU的其它寄存器(除PC之外)该怎么处理。先说第一点,因为任务是第一次运行,而任务从本质上将就是一段代码,所以PC指针应该定位到这段代码的第一行处,即所谓的入口地址(Entry Point)处,这个地址由任务指针保存着,所以把该指针值赋给PC即可。第二,这段代码还未被执行过,所以代码中的变量与CPU的其它寄存器一点关系也没有,因此R0-R12,R14可随便给值,或者不赋值也可,让这些寄存器保持原来的值,显然后者更为简单。最后再给CPSR赋值,用户可以根据实际需要使系统运行于系统模式或管理模式。经过入栈和出栈,此时SP指向任务堆栈的最底端(就是已经定义好的任务堆栈数组的最后一个元素)。之后任务代码开始正式运行,因为CPU的寄存器是有限的,所以在运行时不可避免地要把一些临时变量暂时保存到堆栈中。具体应保存到哪个地址呢,不用担心,SP知道(任务第一次运行时,这个地址就是任务堆栈数组的最后一个元素的地址)。任务堆栈的大小和任务代码中临时变量的数目有关,如果这段代码临变量特别多,堆栈就应设计的大一些。然后,TPrint任务由于某种原因将要被挂起,所以应把任务的运行现场放到堆栈里保护起来,TPrint任务再次运行时再把这个现场还原,任务就能从上次断点处紧接着运行。那么,这个现场是什么呢?从本质上讲,TPrint任务的运行过程就是CPU在执行一段特定的代码,所以这个现场就是CPU的现场,也就是寄存器的值。这些寄存器的值包含了代码执行时的所有信息,包括当前运行到了这段代码的哪个位置处(由PC值指明)。因此,把CPU的寄存器的值推入堆栈,然后记住栈顶指针的位置(SP由OSTCBCur->OSTCBStkPtr保存),当任务再次将要运行前,从SP指向的地址处依次把先前保存的CPU寄存器的值放到CPU的寄存器中,任务就可以从上次中断的地方准确无误地执行。这个过程就像突然把任务冻结了,与任务有关的任何东西都不能动了,一段时间之后又把任务解冻,与它有关的东西又变得可用,于是任务又可以活蹦乱跳地跑起来了。从以上分析可以看出,任务堆栈至始至终伴随着任务,与之生死与共,它的作用可以概括为两点:第一,当任务运行时,它用来保存一些局部变量;第二,当任务挂起时,它负责保存任务的运行现场,也就是CPU寄存器的值。有些朋友正是忽视了第一点,产生了“任务堆栈大小应是固定值的疑问”。我感觉,这可能与对函数OSTaskStkInit()的理解有关,我们都称之为堆栈初始化函数,但此处的“初始化”与我们理解的初始化不太一样,平时讲的(变量的)初始化似乎指的是将变量的所有成员都一一初始化。而此处的堆栈的初始化仅仅是初始化了很大一个堆栈的一小部分,因为当前只有这部分是有用的,而剩余的大部分用不到,所以不用初始化,就像有些变量不用初始化一样(有默认值或随机值)。更深入一点考虑,当任务挂起时,任务堆栈中保存任务挂起前CPU寄存器的这一连续的区域肯定在整个堆栈的最上面;当任务重新开始运行时,SP弹出寄存器的值,这段区域变成空白的区域。而且,任务每次挂起前用来保存当前CPU寄存器这一连续区域在整个任务堆栈空间中是浮动的。

uCOS任务堆栈的深入分析(转)相关推荐

  1. ucos ii堆栈大小检测

    在使用ucos ii时经常会有疑问,这个堆栈该给多大,虽然ucos ii 自带了任务堆栈检测,但是我觉得太麻烦了,而且还会占用资源,我投机取巧的使用内存是否为0来判断堆栈是否使用过,进而检测出堆栈的最 ...

  2. ucosii任务堆栈的作用是什么呢?

    第一,当任务运行时,它用来保存一些局部变量: 第二,当任务挂起时,它负责保存任务的运行现场,也就是CPU寄存器的值. uCOS任务堆栈的深入分析(转) 堆栈作用的就是用来保存局部变量,从本质上讲也就是 ...

  3. stm32开发问题集锦

    1 在flash中跑程序时,能进入中断,但在ram中跑时,进不了中断的原因. 看以下的中断配置函数可以知道,要在ram中调试程序,需要定义VECT_TAB_RAM. 定义方法a:在Project\Op ...

  4. ucosiii系统中的任务管理

    前言:   多任务操作系统最重要的就是对任务进行管理,包括任务的创建,挂起,删除和调度等,因此对于ucosiii操作系统中任务管理的理解就显得尤为重要了.   分几个部分介绍:     1:任务状态 ...

  5. 016_《Delphi源代码分析》

    <Delphi源代码分析> Delphi 教程 系列书籍 (016) <Delphi源代码分析> 网友(邦)整理 EMail: shuaihj@163.com 下载地址: Pa ...

  6. UCOS III 任务堆栈理解

    UCOS III在创建任务时,调用OSTaskStkInit函数,以初始化正在创建的任务的堆栈框架. 1:堆栈就是一段连续的空间.用于存储数据的,在c计算机中有很多应用,比如发生中断时保存现场,c语言 ...

  7. ucos检测任务堆栈使用大小的方法

    今天调试公司前人留下的程序,发现在使用ucos系统时程序一直进入HardFault_Handler硬件中断,经过排查,猜测可能是因为任务堆栈溢出导致,于是想使用ucos自身任务堆栈检测功能测量一下任务 ...

  8. 深入分析MCU堆栈的作用,以及该如何设置堆栈大小

    置顶/星标公众号,不错过每一条消息 前段时间分享文章<从嵌入式编程中感悟「栈」为何方神圣?>之后,很多朋友问了关于堆栈的问题.今天就写点相关内容,让大家进一步了解堆栈的知识. 1写在前面 ...

  9. Linux堆内存管理深入分析(上)

    Linux堆内存管理深入分析 (上半部) 作者:走位@阿里聚安全   0 前言 近年来,漏洞挖掘越来越火,各种漏洞挖掘.利用的分析文章层出不穷.从大方向来看,主要有基于栈溢出的漏洞利用和基于堆溢出的漏 ...

最新文章

  1. 程序员搞事!动手实战优化自己公司线上系统JVM,结果。。。
  2. Sublime Text 安装插件的方法
  3. Entity Framework Core 2.0 使用入门
  4. C#、C++、JAVA中虚函数和抽象函数的概念对比
  5. 【BZOJ2073】[POI2004]PRZ 状压DP
  6. 8004.ros2中添加boost依赖库写法
  7. html中searchbutton点击没有反应,点击按钮加载完整的HTML后,使用Selenium加载其他元素...
  8. 567.字符串的排列
  9. 计算机工作日志如何调取,怎样查找电脑日志?
  10. 《数字电路与逻辑设计》笔记及经典问答题
  11. smartsvn.license
  12. matlab legend颜色不变,关于MATLAB画图中legend标注曲线颜色不匹配问题
  13. uni-app升级后图片上传至阿里云OSS报403错误
  14. 蔡颖-《APS走向实践》书解读之一:APS优化供应链从绩效指标开始
  15. kaldi 学习笔记-三音素训练1(Decision Tree)
  16. python安装0x80072ee7_错误代码为 0x80072EE7 - 卡饭网
  17. PHP微信固码免签系统源码+带监控APP和教程
  18. React技术栈探究-Redux
  19. python程序员教你用微信给对方定位!你说回家!却还在外面鬼混?
  20. 第十五周学习周报(20180611-20180617)

热门文章

  1. 最终计算供应链管理生产计划排程逻辑管理
  2. 前后端分离与前后端不分离的区别
  3. time、random以及序列化模块
  4. CentOS7下安装Docker-Compose
  5. 从测试角度对测试驱动开发的思考【转】
  6. node.js的下载,安装以及卸载
  7. 浪潮存储双活方案:新疆道路运输管理局的大数据应用不再是梦
  8. thinkphp-许愿墙-2
  9. Git学习(一)(2015年11月12日)
  10. Android中基于Socket的网络通信