关闭
搜索
搜索
本版
帖子
用户
热搜:
程序员
简洁模式
高级模式
用户组: 游客
消息
提醒
新听众
我关注的
帖子
道具
勋章
任务
设置
退出
请
登录
后使用快捷导航
没有帐号?
立即注册
设为首页
收藏本站
开启辅助访问
切换到窄版
登录
or
立即注册
快捷导航
搜索
首页
论坛
BBS
MCU单片机技术
程序员交流
从任务的“出生”到“消亡”,ucos任务堆栈关键作用分析
[复制链接]
作者:
崩死菊花虫
版块:
›
嵌入式操作系统
›
其他嵌入式相关
发布时间:
2018-7-22 18:53:03
1125
0
返回列表
崩死菊花虫
当前离线
新手上路
新手上路, 积分 1, 距离下一级还需 49 积分
新手上路
新手上路, 积分 1, 距离下一级还需 49 积分
积分
1
发消息
楼主
电梯直达
崩死菊花虫
发表于 2018-7-22 18:53:03
|
只看该作者
|
倒序浏览
|
阅读模式
定义
首先理解一下两个概念:
堆栈
就是一段连续的空间,用于存储数据的,在C计算机中有很多应用,比如发生中断时保存现场,C语言函数调用时保存现场和临时变量。
堆栈指针
就是一个数据指针。有时候计算机自己更改其指针指向的位置来保存数据,如中断时,有时候我们程序员更改其值,比如ucos操作系统做任务切换时。
堆栈的作用就是用来保存局部变量,从实质上讲也就是将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寄存器这一连续区域在整个任务堆栈空间中是浮动的。
1.
电子刊,不妨来一份儿!
2.嵌入式是个大坑,很多人还要跳!
3.2017年,10种编程语言中哪项能获得更多奖金?
4.物联网时代,开源要怎么玩?
5.科学知识太抽象?设计公司 Moment 想把混合现实技术引入课堂
6.这位工程师用高科技浪漫求婚,学着点不愁女朋友!
免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证
明材料确认版权并支付稿酬或者删除内容。
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有帐号?
立即注册
收藏
0
相关帖子
•
Linux之父怒删工程师提交的补丁,称“太蠢了”网友:怼得好!
•
那些知名的软件开发技术堆栈,看到缩写别懵
•
Linux系统调用原理
•
Linuxx86和ARM什么区别?
•
初学者是先学STM8,还是学STM32?
•
IOT安全——stm32从做题到复现
•
Linux或将限制模块调用某些寄存器
•
Ansible自动化工具安装、配置和快速入门指南|Linux中国
•
STM32RTC及定时闹钟功能实现
•
这些Linux的“自动化”技巧,教你轻松完成任务
回复
使用道具
举报
返回列表
高级模式
B
Color
Image
Link
Quote
Code
表情
@朋友
您需要登录后才可以回帖
登录
|
立即注册
本版积分规则
发表回复
回帖后跳转到最后一页
浏览过的版块
IT业界资讯
快速回复
返回顶部
返回列表