Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304366
  • 博文数量: 85
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 800
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-18 15:21
文章分类

全部博文(85)

文章存档

2017年(1)

2016年(19)

2015年(55)

2014年(10)

我的朋友

分类: 嵌入式

2014-11-26 22:55:31

在ucosII中提供了内存管理的几个函数,其功能是主要是为动态地分配内存和释放内存,充分地利用内存。ucosII的内存管理采用了较为“简单”的架构算法,使得用户可以从不同的内存分区中得到不同大小的内存块,同时在释放的时候将重新放回之前位置。
这里说的架构,是指用户可以定义较大的数组,一般是二维数组,每块的size为数组的二组的列数(第二维),总块数为数组行数(第一维)。
上面指的算法是一种按照单向链接的链表的算法,初始每块的首存放下的一块首地址,并有一指针记录当前的空闲的地址(初始的时候指向第一块)。需要使用的时候从当前空闲块指针取,并将空闲块的指针指向下一块可用的块。呵呵,这就是所谓的"单向链表"。那使用完后又是怎样的呢?就是当前块首存储空闲块指针,而后,空闲块指针需要得到当前使用完块的地址(即空闲块指针=当前使用完块的地址)。注意下这个先后顺序。

来看看ucosII的源码吧。
以下是创建内存块的函数实现代码

点击(此处)折叠或打开

  1. OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)
  2. {
  3.     INT8U *pblk;
  4.     void **plink;
  5.     plink = (void **)addr;
  6. //....
  7. //代码有省略
  8.    /* Create linked list of free memory blocks */
  9.     plink = (void **)addr;     //第1处
  10.     pblk = (INT8U *)addr + blksize;//第2处
  11.     for (i = 0; i < (nblks - 1); i++) {
  12.         *plink = (void *)pblk; //第3处
  13.         plink = (void **)pblk; //第4处
  14.         pblk = pblk + blksize;
  15.     }
  16. //....
  17. //代码有省略

  18. }


咋一看,是不是对(void **)然后又(void*)这些强制转换晕了?确实,我第一次也晕了,醉了。不过也很佩服这种用法的“老道”与娴熟。这也是看OS的源码的值得学习的地方——代码的优美,使用的精炼又准确,周全也顾及阅读感受。
对(void **)与(void *)糊涂的读者,建议百度,笔者推荐CSDN博文《理解*(void**)b》。需要指明的是
若定义了 void *p;
1,(void **)p,将p强制为指向指针(该指针指向void型)的指针,p指向的类型是固定的了,就是指针(该指针指向void型);
2,(void *)p,p指针指向的类型就不固定了
第1处和第2处,强制转换就是类型匹配。
第3处 *plink = (void *)pblk,将pblk强制后赋值给plink指向单元,i=0,就是赋给第一块的块首。也就是说,第一块块首存储着第二块的地址了。
第4处是plink = (void **)pblk什么意思呢?将pblk强制转换成指向指针的指针,所以pblk还是指针嘛,本质没有变化。这句话的意思就是将指针指向的单元地址赋给plink。
那么问题来了。。为什么要强制成(void **)呢?
答案就在上面说的(void **)p的含义,p指向的类型是固定的了,就是指针(该指针指向void型)

那么再看看获得内存块函数void  *OSMemGet (OS_MEM *pmem, INT8U *err)
主要就是以下两条语句
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
       pblk                = pmem->OSMemFreeList //当前空闲块的地址取出
     
      pmem->OSMemFreeList = *(void **)pblk;  //pblk就指向空闲块了,空闲块的首地址的存储值(存放的是下一块可以使用的地址)取出赋给空闲块地址

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
两条语句的含义见注解。可见,这就是链表的指向算法,一链扣一链。
这个获得内存的函数有要求,每次调用只能获得一块。可以对其进行扩展,加入需要获取的内存块数这一参数,满足获得多块的需求。

释放内存函数OSMemPut (OS_MEM  *pmem, void *pblk),也是同理,就不在赘述了。

下面上一张OSMemCreate的示意图,从邵贝贝的ucosII中截取的。

2014-11-28 23:55:06

阅读(2094) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~