欣欣学习网,老工程师带你学习单片机技术,欢迎来坐坐。
首  页 | 学习NIOSII | 学习C51 | 学习CPLD | 51+CPLD实验板 | | | MY-RTOS

 系统简介
 系统启动
 创建任务
 等待与休眠
 使用互斥量
 使用信号量
 信号量组
 使用事件
 使用事件组
 消息队列
 动态内存管理
 只读内存管理
 临界段与内核锁
 任务复位与终止


玛雅实时操作系统(MY-RTOS)

动 态 内 存 管 理


版权声明:玛雅实时操作系统(MY-RTOS)软件及其说明文档由 欣欣学习网 版主 Stoneway QI 创作,作者保留其版权。任何人可以免费在其产品设计或著作中使用或引用该软件及其说明文档,但要求保留原作品当中的版权声明,并注明引用段落的出处。

-- Stoneway QI 主页: http://www.xxworks.com 邮箱: Stonewayqi@hotmail.com

玛雅系统为应用程序提供动态内存管理。其管理方式为分块式内存管理,所管理的随机内存块的大小有6种,分别为20字节、36字节、68字节、132字节、260字节和516字节。由于内存的分配与回收是按固定大小的内存块的方式进行的,所以不存在内存碎片问题。当应用程序向系统申请内存时,系统会从内存库中挑出符合要求的最小的内存块予以分配。为了方便应用程序对大量数据的管理,玛雅系统提供了内存块队列的服务。通过将大量的内存块连成内存块队列,应用程序可以存贮或传递更多的数据,并保持数据的先后次序。

在玛雅系统中,内存块具有归属属性,即:每个内存块都有其所有者。系统内存库中的内存块归内核所有,由应用程序申请下来的内存块归申请该内存块的任务所有,加入队列的内存块归队列所有。内存块的归属权在此三者间变换,不存在没有归属的内存块。系统通过内存块的归属属性对其追踪,防止内存泄露发生。当一个任务被复位或者终止时,系统会自动将其所属的内存块收归内核所有,以便重新分配。对于内存队列中的内存块,也可以通过调用相关的系统函数交还内核。

任务通调用系统函数OSAllocateBlock()向系统申请内存,并通过调用系统函数OSFreeBlock()向系统归还内存。函数OSAllocateBlock()有两个入口参数,第1个入口参数的值为所要申请的内存的大小,第2个入口参数的值代表检索方式。在玛雅系统中,共有两种检索空闲内存块的检索方式。第1种方式是OS_MBLK_FIX,按这种方式检索时,只检索大于所申请内存大小的最小的内存块种类,第2种方式是OS_MBLK_UNFIX,该方式下将检索所有的内存块种类。当内存申请成功时,函数OSAllocateBlock()将返回内存块的起始地址,不成功时则返回一个NULL值。函数OSFreeBlock()的入口参数值为内存块的起始地址,它没有返回人值。任务向系统申请存及归还内存的示例代码如下:

...
void main(void)
{
    U8 * pMem;

    BSP(); // 硬件初化
    OSInit(72000); //玛雅系统初始化
    ...
    while(1)
    {
        ...
        pMem = OSAllocateBlock(64, OS_MBLK_FIX);  //向系统申请内存,要求大小为64个字节
        if(pMem != NULL)                          //指针不为空则申请成功
        {
            ...                                   //使用该内存块
            OSFreeBlock(pMem);                    //将内存块归还系统
        }
    }
}                       (1)

任务可以把申请到的内存块加到内存块队列中去,以便传给其它的任务或保存在内存块队列中。向内存块队列中加入内存块的系统函数为OSAppendBlockTo()。该函数有两个入口参数,第1个入口参数的值为内存块队列索引的地址,第2个参数的值为所要操作的内存块的起始地址。内存块队列索引是用来引用内存块队列的变量,玛雅系统要求该变量要被定义成全局变量或静态局部变量。在使用之前,要对该变量赋予初值,其两个成员的初值匀为该变量的地址。新加入内存块队列的内存块将被放置于内存块队列的末端。

...
void main(void)
{
    static OS_QUEUE MemQ = {&MemQ, &MemQ};
    U8 * pMem;
    ...    
    while(1)
    {
        ...
        pMem = OSAllocateBlock(64, OS_MBLK_FIX);
        if(pMem != NULL)
        {                                               
            ...
            OSAppendBlockTo(&MemQ, pMem);  //将处理过的内存块加入内存块队列中
        }
        ...
    }
}                       (2)

从内存块队列中取回内存块需要调用系统函数OSGetBlockFrom()。该函数的入口参数值为内存块队列索引的地址,若返回值为NULL则表明该内存块队列中已没有内存块,否则返回值为所取得的内存块的起始地址。该函数所取得的内存块来自内存块队列的起始端。

...
void main(void)
{
    static OS_QUEUE MemQ = {&MemQ, &MemQ};
    U8 * pMem;
    ...    
    while(1)
    {
        ...
        pMem = OSGetBlockFrom(&MemQ);  //从内存块队列中摘取1个内存块
        if(pMem != NULL)               //返回值不为NULL则表明取到内存块
        {                                               
            ...
        }
        ...
    }
}                     (3)

在玛雅系统中,任务间传递内存块要通过内存块队列来进行,不可以通过指针来传递。

要清空一个内存块队列,可以通过调用系统函数OSFreeQueue()来实现。该函数会将内存块队列中的所有内存块归还于系统,使该内存块队列成为空队列。

...
void main(void)
{
    static MemQ = {&MemQ, &MemQ};
    ...
    ...    
    while(1)
    {
        ...
        OSFreeQueue(&MemQ);  //清空内存块队列
        ...
    }
}                       (4)

有时,需要将两个内存块队列合并成一个队列,这时可以调用系统函数OSAppendQueueTo()来完成。该函数将源队列中的所有内存块按原来的次序连接到目的队列的末端,源队列则变成一个空队列。它有两个入口参数,第1个入口参数值为目的队列的索引的地址,第2个参数值为源队列的索引的地址。

...
void main(void)
{
    static MemQ1 = {&MemQ1, &MemQ1};
    static MemQ2 = {&MemQ2, &MemQ2};
    ...
    ...    
    while(1)
    {
        ...
        OSAppendQueueTo(&MemQ1, &MemQ2);  //将内存块队列MemQ2合并到MemQ1中去
        ...
    }
}                       (5)

玛雅系统中,对动态内存的分配是按固定大小的内存块进行的,所以,所分配给应用程序的内存块有可能大于应用程序所申请的大小。有些情况下,应用程序需要了解其得到的内存块的真实大小,这时可以调用系统函数OSGetMemSize()来实现。

...
void main(void)
{
    static MemQ = {&MemQ, &MemQ};
    U8 * pMem;
    U16 i;
    ...
    ...    
    while(1)
    {
        ...
        pMem = OSGetBlockFrom(&MemQ);  //从内存块队列中摘取一个内存块
        if(pMem != NULL)
        {
            i = OSGetMemSize(pMem);    //获得该内存块的大小
            ...
        }
        ...
    }
}                       (6)

当任务申请内存失败时,可以通过等待内存信号量的方式来得知是否有合适的内存块被归还于系统,以便再次申请该内存。取得内存信号量的函数为OSGetRamPhores()。

...
void main(void)
{
    OS_SEM * pSem;
    U8 * pMem;
    ...
    pSem = OSGetRamPhores(64);
    while(1)
    {
        ...
        pMem = OSAllocateBlock(64, OS_MBLK_FIX);       //向系统申请内存
        while(pMem == NULL)               
        {
            OSWaitSem(pSem, -1);          //不成功则等待内存信号量
            pMem = OSAllocateBlock(64, OS_MBLK_FIX);   //重新申请
        }
        ...
    }
}                       (7)

玛雅系驻中所提供的动态内存管理是面向任务的管理,不支持中断服务程序中使用动态内存。在中断服务程序中调用动态内存管理的相关函数会导致系统错误。


管理员信箱: stonewayqi@hotmail.com

欣 欣 学 习 网

粤ICP备2023138008号