UcOS-II内存管理.

Slides:



Advertisements
Similar presentations
2.5 函数的微分 一、问题的提出 二、微分的定义 三、可微的条件 四、微分的几何意义 五、微分的求法 六、小结.
Advertisements

阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Oracle数据库 Oracle 子程序.
2-7、函数的微分 教学要求 教学要点.
嵌入式系统概论 —基于32位微处理器与实时操作系统 第五讲实时操作系统C/OS-Ⅱ分析 北京航空航天大学 机器人研究所 魏洪兴.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
陈香兰 助教:陈博、李春华 Spring 2009 嵌入式操作系统 陈香兰 助教:陈博、李春华 Spring 2009.
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
UCOS -II的使用 撰写:李湧 2006-06-29.
走进编程 程序的顺序结构(二).
辅导课程六.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Windows网络操作系统管理 ——Windows Server 2008 R2.
嵌入式系统 —嵌入式实时操作系统C/OS-Ⅱ分析 2006年5月.
以ISI平台为例,为您演示一下如何在Endnote文献中查看该文献的References
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
《手把手教你学STM32》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司 淘宝店铺:
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
《手把手教你学STM32-UCOS》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
第4章 非线性规划 4.5 约束最优化方法 2019/4/6 山东大学 软件学院.
第一章 函数与极限.
3. µC/OS-II内核 2019/4/11.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
内容摘要 ■ 课程概述 ■ 教学安排 ■ 什么是操作系统? ■ 为什么学习操作系统? ■ 如何学习操作系统? ■ 操作系统实例
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
$9 泛型基础.
顺序表的删除.
UcOS-II任务之间的通讯与同步.
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
实验四、TinyOS执行机制实验 一、实验目的 1、了解tinyos执行机制,实现程序异步处理的方法。
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
Ch6. uC/OS-II分析 宋健建 南京大学软件学院.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
Lightweight Data-flow Analysis for Execution-driven Constraint Solving
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
信号量(Semaphore).
第4章 Excel电子表格制作软件 4.4 函数(一).
《手把手教你学STM32-UCOS》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司
本节内容 Private Memory 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
iSIGHT 基本培训 使用 Excel的栅栏问题
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Chapter 18 使用GRASP的对象设计示例.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
Visual Basic程序设计 第13章 访问数据库
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
HSC高速输出例程 HORNER APG.
Ch7 uC/OS-II分析(2) 宋健建 南京大学软件学院 2006/11.
3.1私有内存的分配.
临界区问题的硬件指令解决方案 (Synchronization Hardware)
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
WSAAsyncSelect 模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang
第六章 Excel的应用 五、EXCEL的数据库功能 1、Excel的数据库及其结构 2、Excel下的数据排序 (1)Excel的字段名行
阻塞式模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang 官网地址:
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
本节内容 导出表 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第8章 创建与使用图块 将一个或多个单一的实体对象整合为一个对象,这个对象就是图块。图块中的各实体可以具有各自的图层、线性、颜色等特征。在应用时,图块作为一个独立的、完整的对象进行操作,可以根据需要按一定比例和角度将图块插入到需要的位置。 2019/6/30.
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
创建、启动和关闭Activity 本讲大纲: 1、创建Activity 2、配置Activity 3、启动和关闭Activity
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
本节内容 SEMAPHORE 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
《手把手教你学STM32-STemWin》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司
多个Activity的使用 本讲大纲: 1、使用Bundle在Activity之间交换数据 2、调用另一个Activity并返回结果
Presentation transcript:

ucOS-II内存管理

内存管理 在ANSI C中可以用malloc()和free()两个函数动态地分配内存和释放内存。 在嵌入式实时操作系统中,多次这样做会把原来很大的一块连续内存区域,逐渐地分割成许多非常小而且彼此又不相邻的内存区域,也就是内存碎片。 由于这些碎片的大量存在,使得程序到后来连非常小的内存也分配不到。在任务堆栈中用malloc()函数来分配堆栈时,曾经讨论过内存碎片的问题。 由于内存管理算法的原因,malloc()和free()函数执行时间是不确定的。

内存管理(续) 在μC/OS-II中,操作系统把连续的大块内存按分区来管理。每个分区中包含有整数个大小相同的内存块,如图所示。利用这种机制,μC/OS-II 对malloc()和free()函数进行了改进,使得它们可以分配和释放固定大小的内存块。这样一来,malloc()和free()函数的执行时间也是固定的了。

内存管理(续) 如图所示,在一个系统中可以有多个内存分区。这样,用户的应用程序就可以从不同的内存分区中得到不同大小的内存块。但是,特定的内存块在释放时必须重新放回它以前所属于的内存分区。采用这样的内存管理算法,上面的内存碎片问题就得到了解决。

内存控制块 typedef struct { void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree;} OS_MEM; 为了便于内存的管理,在μC/OS-II中使用内存控制块(memory control blocks)的数据结构来跟踪每一个内存分区,系统中的每个内存分区都有它自己的内存控制块。 .OSMemAddr是指向内存分区起始地址的指针。它在建立OSMemCreate()内存分区时被初始化,在此之后就不能更改了。 .OSMemFreeList是指向下一个空闲内存控制块或者下一个空闲的内存块的指针,具体含义要根据该内存分区是否已经建立来决定。 .OSMemBlkSize是内存分区中内存块的大小,是用户建立该内存分区时指定的。 .OSMemNBlks是内存分区中总的内存块数量,也是用户建立该内存分区时指定的。 .OSMemNFree是内存分区中当前可以得到的空闲内存块数量。

内存控制块链表 如果要在μC/OS-II中使用内存管理,必须将OS_CFG.H文件中的开关量OS_MEM_EN设置为1。这样μC/OS-II 在启动时就会对内存管理器进行初始化[由OSInit()调用OSMemInit()实现]。该初始化主要建立一个如图所示的内存控制块链表,其中的常数OS_MAX_MEM_PART(见文件OS_CFG.H)定义了最大的内存分区数,该常数值至少应为2。

建立一个内存分区 OS_MEM *CommTxBuf; INT8U CommTxPart[100][32];   void main (void) { INT8U err;   OSInit(); . . CommTxBuf = OSMemCreate(CommTxPart, 100, 32, &err); . . OSStart(); } 在使用一个内存分区之前,必须先建立该内存分区。这个操作可以通过调用OSMemCreate()函数来完成。上面的程序清单说明了如何建立一个含有100个内存块、每个内存块32字节的内存分区。

建立一个内存分区OSMemCreate() OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err) /4个参数:内存分区的起始地址、分区内的内存块总数、每个内存块的字节数和一个指向错误信息代码的指针。 { OS_MEM *pmem; INT8U *pblk; void **plink; INT32U i;   if (nblks < 2) {(1) /每个内存分区必须含有至少两个内存块 *err = OS_MEM_INVALID_BLKS; return ((OS_MEM *)0); } if (blksize < sizeof(void *)) {(2) /每个内存块至少为一个指针的大小,因为同一分区中的所有空闲内存块是由指针串联起来的 *err = OS_MEM_INVALID_SIZE; return ((OS_MEM *)0); } OS_ENTER_CRITICAL(); pmem = OSMemFreeList; (3) /从系统中的空闲内存控制块中取得一个内存控制块 if (OSMemFreeList != (OS_MEM *)0) { OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList; } OS_EXIT_CRITICAL(); if (pmem == (OS_MEM *)0) {(4) /在空闲内存控制块可用的情况下才能建立一个内存分区 *err = OS_MEM_INVALID_PART; return ((OS_MEM *)0); }

建立一个内存分区OSMemCreate()(续) plink = (void **)addr; (5) /上述条件均满足时,所要建立的内存分区内的所有内存块被链接成一个单向的链表 pblk = (INT8U *)addr + blksize; for (i = 0; i < (nblks - 1); i++) {*plink = (void *)pblk; plink = (void **)pblk; pblk = pblk + blksize; } *plink = (void *)0; OS_ENTER_CRITICAL(); pmem->OSMemAddr = addr; (6) /在对应的内存控制块中填写相应的信息 pmem->OSMemFreeList = addr; pmem->OSMemNFree = nblks; pmem->OSMemNBlks = nblks; pmem->OSMemBlkSize = blksize; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (pmem); (7) /返回指向该内存块的指针,该指针在以后对内存块的操作中使用。 }

OSMemCreate() 后内存控制块及对应的内存分区和分区内的内存块之间的关系 在程序运行期间,经过多次的内存分配和释放后,同一分区内的各内存块之间的链接顺序会发生很大的变化。

分配一个内存块OSMemGet() 用户可以在中断服务子程序中调用OSMemGet() 。 void *OSMemGet (OS_MEM *pmem, INT8U *err) (1) /参数中的指针pmem指向用户希望从其中分配内存块的内存分区 { void *pblk;   OS_ENTER_CRITICAL(); if (pmem->OSMemNFree > 0) {(2) /首先检查内存分区中是否有空闲的内存块 pblk = pmem->OSMemFreeList; (3) /如果有,从空闲内存块链表中删除第一个内存块 pmem->OSMemFreeList = *(void **)pblk; (4) /对空闲内存块链表作相应的修改 pmem->OSMemNFree--; (5) /包括将链表头指针后移一个元素和空闲内存块数减1 OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (pblk); (6) /返回指向被分配内存块的指针 } else {OS_EXIT_CRITICAL(); *err = OS_MEM_NO_FREE_BLKS; return ((void *)0); } } 用户可以在中断服务子程序中调用OSMemGet() 。

释放一个内存块OSMemPut() INT8U OSMemPut (OS_MEM *pmem, void *pblk) (1) /第一个参数pmem是指向内存控制块的指针,也即内存块属于的内存分区 { OS_ENTER_CRITICAL(); if (pmem->OSMemNFree >= pmem->OSMemNBlks) {(2) /首先检查内存分区是否已满,如果已满,说明系统在分配和释放内存时出现了错误。 OS_EXIT_CRITICAL(); return (OS_MEM_FULL); } *(void **)pblk = pmem->OSMemFreeList; (3) /如果未满,要释放的内存块被插入到该分区的空闲内存块链表中 pmem->OSMemFreeList = pblk; pmem->OSMemNFree++; (4) /将分区中空闲内存块总数加1 OS_EXIT_CRITICAL(); return (OS_NO_ERR); } 当用户应用程序不再使用一个内存块时,必须及时地把它释放并放回到相应的内存分区中。

查询一个内存分区的状态OSMemQuery() typedef struct { void *OSAddr; / 指向内存分区首地址的指针 void *OSFreeList; / 指向空闲内存块链表首地址的指针 INT32U OSBlkSize; / 每个内存块所含的字节数 INT32U OSNBlks; / 内存分区总的内存块数 INT32U OSNFree; / 空闲内存块总数 INT32U OSNUsed; / 正在使用的内存块总数 } OS_MEM_DATA; 在μC/OS-II 中,使用OSMemQuery()函数来查询一个特定内存分区的有关消息(如特定内存分区中内存块的大小、可用内存块数和正在使用的内存块数等信息),所有这些信息都放在一个OS_MEM_DATA的数据结构中。

查询一个内存分区的状态OSMemQuery() INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *pdata) { OS_ENTER_CRITICAL(); /首先禁止了外部中断,防止复制过程中某些变量值被修改 pdata->OSAddr = pmem->OSMemAddr; (1) /将指定内存分区的信息复制到OS_MEM_DATA定义的变量的对应域中 pdata->OSFreeList = pmem->OSMemFreeList; pdata->OSBlkSize = pmem->OSMemBlkSize; pdata->OSNBlks = pmem->OSMemNBlks; pdata->OSNFree = pmem->OSMemNFree; OS_EXIT_CRITICAL(); pdata->OSNUsed = pdata->OSNBlks - pdata->OSNFree; (2) /由于正在使用的内存块数是由OS_MEM_DATA中的局部变量计算得到的,所以,可以放在临界段代码的外面。 return (OS_NO_ERR); }

使用内存分区Using Memory Partitions 图示为一个演示如何使用μC/OS-II中的动态分配内存功能,以及利用它进行消息传递的例子。 第一个任务读取并检查模拟输入量的值(如气压、温度、电压等),如果其超过了一定的阈值,就向第二个任务发送一个消息。该消息中含有时间信息、出错的通道号和错误代码等可以想象的任何可能的信息。 错误处理程序是该例子的中心。任何任务、中断服务子程序都可以向该任务发送出错消息。错误处理程序则负责在显示设备上显示出错信息,在磁盘上登记出错记录,或者启动另一个任务对错误进行纠正等。

内存分配的例子程序——扫描模拟量的输入和报告出错 AnalogInputTask() { for (;;) {for (所有的模拟量都有输入) {读入模拟量输入值; (1) if (模拟量超过阈值) {得到一个内存块; (2) 得到当前系统时间 (以时钟节拍为单位); (3) 将下列各项存入内存块: (4) 系统时间 (时间戳); 超过阈值的通道号; 错误代码;错误等级; 等. 向错误队列发送错误消息; (5) (一个指向包含上述各项的内存块的指针) } } 延时任务,直到要再次对模拟量进行采样时为止; } }    ErrorHandlerTask() { for (;;) {等待错误队列的消息; (6) (得到指向包含有关错误数据的内存块的指针) 读入消息,并根据消息的内容执行相应的操作; (7) 将内存块放回到相应的内存分区中; (8) } } 例子中两个任务的示意代码,其中一些重要代码的标号和上图中括号内用数字标识的动作是相对应的。

等待一个内存块 有时候,在内存分区暂时没有可用的空闲内存块的情况下,让一个申请内存块的任务等待也是有用的。 但是,μC/OS-II在内存管理上并不支持这项功能。如果确实需要,则可以通过为特定内存分区增加信号量的方法,实现这种功能。 应用程序为了申请分配内存块,首先要得到一个相应的信号量,然后才能调用OSMemGet()函数。

等待从一个内存分区中分配内存块程序 OS_EVENT *SemaphorePtr; (1) /首先定义了程序中使用到的各个变量 OS_MEM *PartitionPtr; INT8U Partition[100][32]; OS_STK TaskStk[1000];   void main (void) { INT8U err;  OSInit(); (2) /系统复位时,μC/OS-II调用OSInit()进行系统初始化 . . SemaphorePtr = OSSemCreate(100); (3) /用内存分区中总的内存块数来初始化一个信号量 PartitionPtr = OSMemCreate(Partition, 100, 32, &err); (4) /建立内存分区 . OSTaskCreate(Task, (void *)0, &TaskStk[999], &err); (5) /建立相应的要访问该分区的任务 . OSStart(); (6) /执行多任务 }

等待从一个内存分区中分配内存块程序(续) void Task (void *pdata) { INT8U err; INT8U *pblock;   for (;;) {OSSemPend(SemaphorePtr, 0, &err); (7) /一个任务运行时,只有在信号量有效时 pblock = OSMemGet(PartitionPtr, &err); (8) /才有可能得到内存块 . . /使用内存块 . OSMemPut(PartitionPtr, pblock); (9) /当一个任务不再使用某内存块时,只需简单地将它释放并返还到内存分区 OSSemPost(SemaphorePtr); (10) /并发送该信号量 } }