找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 16030|回复: 0
打印 上一主题 下一主题
收起左侧

uc/os-ii操作系统的内存管理实现实例--很受用!

[复制链接]
跳转到指定楼层
楼主
ID:72008 发表于 2015-1-12 15:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
     每次 温故uc/os-ii操作系统的源码都有收获,经典的东西就是经典;uc/os-ii曾经把我搞得好累,但是经过一段时间摸索之后发现只要有正确的学习方法,学好uc/os-ii并不难,同时基于uc/os-ii操作系统的应用程序开发也不难。关于嵌入式系统内存管理的方法应该不少,原子的内存管理教程就有两个例程,一个是“特大号数组”型,一个是动态分配型,两者都使用了malloc()函数。而uc/os-ii操作系统的内存管理实现原理很精妙没有使用malloc()函数,主要是考虑该函数申请内存的时间不确定性。可以说,通过该例程就能理解uc/os-ii操作系统的内存管理实现原理。笔者认为通过实例学习,理解uc/os-ii操作系统的原理是个不错的选择。
    本实验基于PC机在DOS环境下模拟。



/*设计一个有3个任务的应用程序,这3个任务分别是Mytask Youtask Hertask。在应用程序中创建一个动态内存分区,该分区有8个内存块,每个内存块的长度是6字节。应用程序的任务Youtask Hertask都在任务运行后请求一个内存块.随后就释放它;任务MYTASK也在任务运行后请求一个内存块,但是要在任务MYTASK运行6次后,才释放它所申请的内存块。为了了解内存分区变化的情况,编写代码来观察分区头指针和已被使用内存块的个数*/


#include "INCLUDES.h"

#define  TASK_STK_SIZE        512       /* 任务堆栈长度*/            

OS_STK        StartTaskStk[TASK_STK_SIZE];    /*定义任务堆栈区 */
OS_STK        MyTaskStk[TASK_STK_SIZE];
OS_STK        YouTaskStk[TASK_STK_SIZE];
OS_STK        HerTaskStk[TASK_STK_SIZE];

char *s;
char *s1= "Mytask  ";
char *s2= "Youtask ";
char *s3= "Hertask ";
INT8U  err;
INT8U  y=0;   //字符显示位置  
INT8U  Times=0;

OS_MEM        *IntBuffer;      /*定义内存控制块指针,创建一个内存分区时,返回值就是它 */
INT8U         IntPart[8][6];  /*划分一个具有8个内存块,每个内存块长度是6的内存分区 */
INT8U         *IntBlkPtr;      /*定义内存块指针,确定内存分区中首个内存块的指针  */
OS_MEM_DATA MemInfo;   /*存放内存分区的状态信息 */

void  StartTask(void *data);               /* 声明起始任务  */
void  MyTask(void *data);                  /* 声明任务      */
void  YouTask(void *data);                 /* 声明任务      */
void  HerTask(void *data);                 /* 声明任务      */

/*
********************************************************************
*              MAIN主函数
**********************************************************************
*/

void  main (void)
{
    OSInit();               /* 初始化uC/OS-II                      */
    PC_DOSSaveReturn();       /* 保存DOS环境     */
    PC_VectSet(uCOS, OSCtxSw);     /* 安装uC/OS-II的中断 */
    IntBuffer=OSMemCreate(IntPart,8,6,&err);    /*创建动态内存区  */
    OSTaskCreate(StartTask, (void *)0, &StartTaskStk[TASK_STK_SIZE - 1], 0);
    OSStart();             /* 启动多任务管理   */
}


/*
***********************************************************
*                STARTUP TASK:主要功能就是创建3个任务
***********************************************************
*/
void  StartTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3      /* Allocate storage for CPU status register,实际应用中该部分可省略 */
    OS_CPU_SR  cpu_sr;
#endif
    INT16S        key;          /*用于退出的建*/
    pdata = pdata;          /* Prevent compiler warning                 */
    OS_ENTER_CRITICAL();
    PC_VectSet(0x08, OSTickISR);      /* 安装时钟中断向量 , */
    PC_SetTickRate(OS_TICKS_PER_SEC);   /* 设置时钟频率 */
    OS_EXIT_CRITICAL();

    OSStatInit();        /* 初始化统计任务   */
    OSTaskCreate(MyTask, (void *)0, &MyTaskStk[TASK_STK_SIZE - 1], 3);
    OSTaskCreate(YouTask, (void *)0, &YouTaskStk[TASK_STK_SIZE - 1], 4);
    OSTaskCreate(HerTask, (void *)0, &HerTaskStk[TASK_STK_SIZE - 1], 5);
   
    for (;;) {
    //如果恩下ESC键,则退出UC/OS-II
        if (PC_GetKey(&key) == TRUE) {   /* See if key has been pressed     */
            if (key == 0x1B) {       /* Yes, see if it's the ESCAPE key    */
                PC_DOSReturn();    /* Return to DOS       */
            }
        }
        OSTimeDlyHMSM(0, 0, 3, 0);   /* Wait 3s,在这里创建完StartTask任务为什么不挂起自己?      */
    }
}

/*--------------------MyTask任务-------------------------*/
void MyTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3       /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr;
#endif
pdata=pdata;
for( ; ; )
{
PC_DispStr(10,++y,s1,DISP_BGND_BLACK+DISP_FGND_WHITE);  /*"++y"执行一次就换一次行  */
IntBlkPtr=OSMemGet(   /*请求内存分区的内存块的指针 */
                 IntBuffer, /*这个参数就指明了要获取的内存块属于哪个内存分区 */  
                 &err);      
   OSMemQuery(        /*查询内存控制块信息 */
            IntBuffer,     /*带查询内存控制块指针 */
&MemInfo);
sprintf(s,"%0x",MemInfo.OSFreeList);  /*显示头指针 */
PC_DispStr(30,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
sprintf(s,"%d",MemInfo.OSNUsed);  /*显示已用的内存块数目 */
PC_DispStr(40,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
if(Times>4)  /*0-1-2-3-4-5;Times==6时该条件语句为真 */
{
OSMemPut(IntBuffer,IntBlkPtr);   /* 进入第6次就释放已经使用过的内存块  */
}
Times++;
OSTimeDlyHMSM(0,0,1,0);  //等待2s
}
}

/*-------------------------------Youtask-------------------------------------*/
void YouTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr;
#endif
pdata=pdata;
for( ; ; )
{
PC_DispStr(10,++y,s2,DISP_BGND_BLACK+DISP_FGND_WHITE);
IntBlkPtr=OSMemGet(            //请求内存块
                 IntBuffer,   //内存分区的指针
                 &err);       //错误信息
   OSMemQuery(        //查询内存控制块信息
            IntBuffer,     //带查询内存控制块指针
&MemInfo);
sprintf(s,"%0x",MemInfo.OSFreeList);  //显示头指针
PC_DispStr(30,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
sprintf(s,"%d",MemInfo.OSNUsed);  //显示已用的内存块数目
PC_DispStr(40,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
OSMemPut( IntBuffer, IntBlkPtr );
OSTimeDlyHMSM(0,0,2,0);  //等待2s
}
}
/*-------------------------------Hertask-------------------------------------*/
void HerTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3      /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr;
#endif
pdata=pdata;
for( ; ; )
{
PC_DispStr(10,++y,s3,DISP_BGND_BLACK+DISP_FGND_WHITE);
IntBlkPtr=OSMemGet(            //请求内存块
                 IntBuffer,   //内存分区的指针
                 &err);       //错误信息
   OSMemQuery(        //查询内存控制块信息
            IntBuffer,     //带查询内存控制块指针
&MemInfo);
sprintf(s,"%0x",MemInfo.OSFreeList);  //显示头指针
PC_DispStr(30,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
sprintf(s,"%d",MemInfo.OSNUsed);  //显示已用的内存块数目
PC_DispStr(40,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
OSMemPut(
IntBuffer,
IntBlkPtr
);
OSTimeDlyHMSM(0,0,1,0);  //等待2s
}
}
/*
通过本例的实验现象能深刻理解内存管理函数的本质;现象分析如下:
y(行)    显示内容:       显示头指针OSFreeList:     显示已用的内存块数目OSNUsed:
1,        MyTask              504                         1
2,        YouTask             50A                         2
3,        HerTask             50A                         2
4,        MyTask              50A                         2
5,        HerTask             510                         3
6,        MyTask              510                         3
7,        YouTask             516                         4
8,        HerTask             516                         4
9,        MyTask              516                         4
10,       HerTask             51C                         5
11,       MyTask              51C                         5
12,       YouTask             522                         6
13,       HerTask             522                         6
14,       MyTask              522                         6
15,       MyTask              522                         6

通过上表可以看出:1,“显示头指针OSFreeList”的数据很有规律,即都是以6为单位递增,这是因为在创建内存控制块时就定义了每个内存块的长度是6个字节,所以就是以6为单位递增,(0x504+0x6)==0x50A;
(0x50A+0x6)==0x510,(0x510+0x6)==0x516,等等; 2,第2行中,因为YouTask任务请求一个内存块之后就立即释放了,所以在第3个任务(HerTask任务)中,HerTask任务申请到的还是50A指针指向的内存块,同样在本任务中及时释放了内存块,实际上此时系统只占用504内存块,所以到第4个任务MyTask 任务执行时,还是显示已用2个内存块,不过这时MyTask 任务已经占用了两个内存块,因为此时MyTask 任务还没有释放内存块;3,当if(Times>4) 时 (0-1-2-3-4-5;Times==6时该条件语句为真)MyTask 任务得到一个内存块就立即释放了该内存块,所以就一直会显示已用6个内存块,指针值停留在0x522处,不会再递增了;4,由此现象得知:a),本例中申请到的8个内存块是连续的地址空间;b),系统在初始化时,就初始化了一个空的任务控制块链表,每个任务控制块的有效数据为空,但是结点指针都有所指;当系统申请一个内存分区时,空闲任务控制块就会减1,释放了就加1;c),整个空闲链表是不是一个大的连续内存空间,还不知道,我觉得应该看OSInit()源码。

*/                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表