【uTenux實驗】內存池管理(固定內存池和可變內存池)

一、固定內存池管理實驗數組

      內存管理是操做系統的一個基礎功能。uTenux的內存池管理函數提供了基於軟件的內存池管理和內存塊分配管理。uTenux的內存池有固定大小的內存池和大小可變的內存池之分,它們被當作是互相獨立的對象,須要不一樣的系統調用集來進行操做。緩存

內存池管理函數管理的內存所有包含在系統空間之內。函數

一、固定尺寸內存池實驗ui

    固定尺寸內存池是一個用來動態管理固定尺寸內存塊的對象。每一個固定尺寸內存池都有一個用做固定尺寸內存池的內存空間(簡稱爲內存池區)和一個等待內存塊分配的任務隊列。this

    uTenux提供了五個供操做固定內存池的API,分別用於建立、刪除、獲取、釋放、查詢內存池狀態。spa

建立固定尺寸內存池,須要提供一個T_CMPF類型的結構體。定義以下:操作系統

 

typedef    struct t_cmpf {
    VP                  exinf;                   /* 擴展信息*/
    ATR                 mpfatr;                     /* 內存池屬性*/
    W                   mpfcnt;                     /* 建立的內存池塊數*/
    W                   blfsz;                     /* 每塊的大小(byte) */
    UB                  dsname[8];               /* Object name */
    VP                  bufptr;                     /* User buffer */
} T_CMPF;

內存池屬性mpfatr是的定義以下:指針

mpfatr:=(TA_TFIFO||TA_TPRI)|TA_USERBUF|TA_DSNAME|(TA_RNG0||TA_RNG1 ||TA_RNG2||TA_RNG3)

TA_TFIFO 等待內存分配的任務按FIFO的順序排隊code

TA_TPRI 等待內存分配的任務按優先級順序排隊對象

TA_RNGn 內存訪問權設置成保護級別n

TA_USERBUF 指示系統使用用戶指定的內存空間

TA_DSNAME 設定DS對象名

      因爲uTenux沒有使用硬件的內存保護功能,TA_RNGn 只能是TA_RNG0。TA_USERBUF是不使用OS提供的內存空間時候使用的。TA_DSNAME基本沒什麼用。

獲取內存池函數:ER ercd= tk_get_mpf(ID mpfid,VP *p_blf,TMO tmout);中,p_blf爲獲取的內存塊的起始地址。爲VP類型,即一個void*的指針。使用時須要注意。

【實驗描述】

一、建立兩個任務一個包含5塊區域的內存池。

二、啓動TaskB,在TaskB中啓動TaskA,TaskA開始執行就當即休眠。等待TaskB喚醒

三、TaskB繼續執行。先輸出當前可用內存塊數目,申請一塊內存後再次輸出內存塊數目。

四、最後將一段數據放入這塊內存。以後喚醒TaskA。

五、TaskA輸出由TaskB放入內存塊的數據以後,釋放內存塊。再次輸出可用內存塊數。。而後進入休眠狀態,TaskB繼續執行。

【代碼及輸出】

固定內存池使用:

#include "MpfSample.h"

void MpfSampleTaskA(W stacd,VP exinf);
void MpfSampleTaskB(W stacd,VP exinf);
void MpfSamplePutCnt(void);
static ID TaskID_A;
static ID TaskID_B;
static ID mpfid;
static VP blf=NULL;

ER MpfSample( void)
{
    ER ercd = E_OK;
    T_CTSK ctsk;
    T_CMPF cmpf;

    tm_putstring((UB*)"Mempool fix sample create Task A;\n");
    ctsk.exinf = (VP)NULL;
    ctsk.tskatr = TA_HLNG | TA_RNG0;
    ctsk.task = MpfSampleTaskA;
    ctsk.itskpri = 24;
    ctsk.stksz = 512;
    TaskID_A = tk_cre_tsk(&ctsk);
    if(TaskID_A < E_OK) {
        ercd=TaskID_A;
        return ercd;
    }
    
    tm_putstring((UB*)"Mempool fix sample create Task B;\n");
    ctsk.task = MpfSampleTaskB;
    ctsk.itskpri = 26;
    TaskID_B = tk_cre_tsk(&ctsk);
    if(TaskID_B < E_OK) {
        ercd=TaskID_B;
        return ercd;
    }
    
    tm_putstring((UB*)"Mempool fix sample create a mempoolf;\n");
    cmpf.bufptr = NULL;
    cmpf.exinf = (VP)NULL;
    cmpf.blfsz = 100;   //100Byte
    cmpf.mpfcnt = 5;  //5塊
    cmpf.mpfatr = TA_TFIFO | TA_RNG0;  //內存池屬性,先到先得 不使用保護
    mpfid = tk_cre_mpf(&cmpf);
 
    tm_putstring((UB*)"Mempool fix sample create a mempoolf successfully;\n");
    MpfSamplePutCnt();

    tm_putstring((UB*)"Mempool fix sample start Task B;\n");
    tk_sta_tsk(TaskID_B,0);
    return TRUE;
} 
 
void MpfSampleTaskA(W stacd,VP exinf)
{
  tm_putstring((UB*)"Task A now enter sleep mode\n");
  tk_slp_tsk(-1);
  while(1)
  {
    tm_putstring((UB*)"Task A read data from the memory block,that is:\n");
    tm_putstring((UB*)blf);
    tk_rel_mpf(mpfid,blf);
    MpfSamplePutCnt();
    tk_slp_tsk(-1);
  }
}

void MpfSampleTaskB(W stacd,VP exinf)
{
  B* buf = "this is utenux\n";
  B blfadd[10];
  tm_putstring((UB*)"Task B now start Task A\n");
  tk_sta_tsk(TaskID_A,0);
  tm_putstring((UB*)"*****************************************\n");
  while(1)
  {
    MpfSamplePutCnt();
    tm_putstring((UB*)"Task B now get a block of memory\n");
    if(E_OK == tk_get_mpf(mpfid,&blf,-1))  //申請內存塊
    {
      MpfSamplePutCnt();
      tm_putstring((UB*)"Task B get memory block sucessfully\nmemory addressis 0x");
      ltostr((UW)blf,blfadd,16,10);
      tm_putstring((UB*)blfadd);  //以字符串形式輸出地址
      tm_putstring((UB*)"\n*****************************************\n");
      memcpy(blf,buf,strlen(buf)+1);
    }
    else
    {
      tm_putstring((UB*)"Task B failed get memory\n");
      break;
    }
    tm_putstring((UB*)"Task B now wake up Task A\n");
    tk_wup_tsk(TaskID_A);
    Delay(0x1000000);
  }
}

void MpfSamplePutCnt(void)
{
    B frbcnt[10];
    T_RMPF rmpf;

    tm_putstring((UB*)"Now Free memory block number is ");
    tk_ref_mpf(mpfid, &rmpf);
    ltostr(rmpf.frbcnt,frbcnt,10,10);
    tm_putstring((UB*)frbcnt);
    tm_putstring((UB*)"\n");
}

輸出:

----------------------------------------------------
        micro Tenux Version 1.6.00(build 0180)     
            Supported MCU is ST STM32F407VG        
  Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd. 
----------------------------------------------------

Mempool fix sample create Task A;
Mempool fix sample create Task B;
Mempool fix sample create a mempoolf;
Mempool fix sample create a mempoolf successfully;
Now Free memory block number is 5
Mempool fix sample start Task B;
Task B now start Task A
Task A now enter sleep mode
*****************************************
Now Free memory block number is 5
Task B now get a block of memory
Now Free memory block number is 4
Task B get memory block sucessfully
memory addressis 0x20002634
*****************************************
。。。。。。。。。。。

二、可變內存池實驗

預備知識:C語言中的內存塊操做函數

1、memcpy
原型:void *memcpy(void *dest, const void *src, size_t n);
功能:從源src所指的內存地址的起始位置開始拷貝n個字節到目標dest所指的內存地址的起始位置中
2、memmove

原型:void *memmove( void* dest, const void* src,size_tcount );

頭文件:<string.h>

功能:由src所指內存區域複製count個字節到dest所指內存區域。

說明memmove用於從src拷貝count個字符到dest,若是目標區域和源區域有重疊的話,memmove可以保證源串在被覆蓋以前將重疊區域的字節拷貝到目標區域中。但複製後src內容會被更改。可是當目標區域與源區域沒有重疊則和memcpy函數功能相同。

3、memcmp
int memcmp(const void *buf1, const void *buf2, unsigned int count);
比較內存區域buf1和buf2的前count個字節。

當buf1<buf2時,返回值<0

當buf1=buf2時,返回值=0

當buf1>buf2時,返回值>0

4、memchr

原型:extern void *memchr(const void *buf, int ch, size_t count);

用法:#include <string.h>

功能:從buf所指內存區域的前count個字節查找字符ch。

說明:當第一次遇到字符ch時中止查找。若是成功,返回指向字符ch的指針;不然返回NULL。

5、memset

void *memset(void *s, int ch, size_t n);

函數解釋:將s中前n個字節(typedef unsigned int size_t)用 ch 替換並返回s。

做用是在一段內存塊中填充某個給定的值,它是對較大的結構體或數組進行清零操做的一種最快方法

可變尺寸內存池是一個用來動態管理任何大小的內存塊的對象。與固定尺寸內存池同樣,每一個可變尺寸內存池都有一個用做可變尺寸內存池的內存空間和一個等待內存塊分配的任務隊列。

可變尺寸內存池管理SVC:

建立可變尺寸內存池:tk_cre_mpl

須要提供參數T_CMPL的定義以下:

 

typedef    struct t_cmpl {
    VP                  exinf;                     /* 擴展屬性*/
    ATR                 mplatr;                     /* 內存池屬性 */
    W                   mplsz;                     /* 內存池的大小 (byte) */
    UB                  dsname[8];               /* Object name */
    VP                  bufptr;                     /* User buffer */
} T_CMPL;

內存池屬性的定義:

mplatr:=(TA_TFIFO||TA_TPRI)|TA_USERBUF|TA_DSNAME|(TA_RNG0||TA_RNG1||TA_RNG2 ||TA_RNG3)

TA_TFIFO 等待內存分配的任務按FIFO的順序排隊

TA_TPRI 等待內存分配的任務按優先級順序排隊

TA_RNGn 內存訪問權設置成保護級別n

TA_USERBUF 指示系統使用用戶指定的內存空間

TA_DSNAME 設定DS對象名

能夠發現,uTenux中各個對象的屬性定義是很類似的:

一、兩種排隊順序TA_TFIFO和TA_TPRI

二、內存保護級別TA_RNGn 必須是TA_RNG0

三、TA_DSNAME對象名

四、TA_USERBUF 用戶緩存

以後就不列出來這東西了。

至於申請,釋放都比較簡單,這裏不一一列出了。

【實驗描述】

本實驗參考源碼包中的09.mempoolv

一、首先建立兩我的物一個大小512字節的內存池。而後啓動任務A,任務A自動休眠等待喚醒。以後啓動任務B。

二、任務B首先輸出可用內存數,以後申請128Byte內存,再次輸出可用內存數。

三、任務B將申請到的內存清空,將數據放入。以後喚醒任務A。

四、任務A優先級高,開始執行。

五、任務A首先輸出任務B放入內存塊的數據,任何釋放這個內存塊。

六、最後任務A再次休眠,任務B開始循環執行。

【實驗代碼和輸出】

#include "MempoolvSample.h"

void MplSampleTaskA(W stacd,VP exinf);
void MplSampleTaskB(W stacd,VP exinf);
void MplSamplePutCnt(void);
static ID TaskID_A;
static ID TaskID_B;
static ID mplid;
static VP blf;

ER MplSample( void)
{
    ER ercd = E_OK;
    T_CTSK ctsk;
    T_CMPL cmpl;

    tm_putstring((UB*)"Mempool variable sample create Task A;\n");
    ctsk.exinf = (VP)NULL;
    ctsk.tskatr = TA_HLNG | TA_RNG0;
    ctsk.task = MplSampleTaskA;
    ctsk.itskpri = 24;
    ctsk.stksz = 512;
    TaskID_A = tk_cre_tsk(&ctsk);
    if(TaskID_A < E_OK) {
        ercd=TaskID_A;
        PutErcd(ercd);
        return ercd;
    }
    
    tm_putstring((UB*)"Mempool variable sample create Task B;\n");
    ctsk.exinf = (VP)NULL;
    ctsk.tskatr = TA_HLNG | TA_RNG0;
    ctsk.task = MplSampleTaskB;
    ctsk.itskpri = 26;
    ctsk.stksz = 512;
    TaskID_B = tk_cre_tsk(&ctsk);
    if(TaskID_B < E_OK) {
        ercd=TaskID_B;
        PutErcd(ercd);
        return ercd;
    }
    
    //本身寫
    tm_putstring((UB*)"Mempool variable sample create a mempool variable;\n");
   
    cmpl.bufptr = NULL;
    cmpl.exinf =(VP)NULL;
    cmpl.mplatr = TA_TFIFO | TA_RNG0;
    cmpl.mplsz = 512;
    mplid = tk_cre_mpl(&cmpl);
    if(E_OK < mplid)
    {
      tm_putstring((UB*)"Mempool variable sample create a mempool successfully;\n");
    }
      
    tm_putstring((UB*)"Mempool variable sample start Task A;\n");
    tk_sta_tsk(TaskID_A,0);
    tm_putstring((UB*)"Mempool variable sample start Task B;\n");
    tk_sta_tsk(TaskID_B,0);

    return TRUE;
} 
 
void MplSampleTaskA(W stacd,VP exinf)
{
  tm_putstring((UB*)"Task A enter sleep status;\n");
  tk_slp_tsk(-1);
  while(1)
  {
    tm_putstring((UB*)"Task A print the contents of the memory block;\n");
    tm_putstring((UB*)blf);
    tm_putstring((UB*)"Task A release mpl,;\n");
    tk_rel_mpl(mplid,blf);
    MplSamplePutCnt();
    
    tk_slp_tsk(-1);
  }
}

void MplSampleTaskB(W stacd,VP exinf)
{
  B* buf = "this is an utenux programme\n";
  B* blfadd[10];//用於存放地址轉換來的字符串
  
  tm_putstring((UB*)"this is in task b\n");
  while(1)
  {
    MplSamplePutCnt(); //輸出申請mpl以前的可用內存字節數
    if(E_OK == tk_get_mpl(mplid,128,&blf,-1))
    {
      MplSamplePutCnt();
      memset(blf,0,128);//清除掉獲取的內存中全部數據
      memcpy(blf,buf,strlen(buf));
      
    }
    Delay(0x1000000);
    tm_putstring((UB*)"Task B wake up Task A\n");
    tk_wup_tsk(TaskID_A);
  }
}

void MplSamplePutCnt(void)
{
    B frsz[10];
    T_RMPL rmpl;

    tm_putstring((UB*)"Now Free memory number is ");
    tk_ref_mpl(mplid, &rmpl);
    ltostr(rmpl.frsz,frsz,10,10);
    tm_putstring((UB*)frsz);
    tm_putstring((UB*)"B\n");
}

輸出:
----------------------------------------------------
        micro Tenux Version 1.6.00(build 0180)     
            Supported MCU is ST STM32F407VG        
  Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd. 
----------------------------------------------------

Mempool variable sample create Task A;
Mempool variable sample create Task B;
Mempool variable sample create a mempool variable;
Mempool variable sample create a mempool successfully;
Mempool variable sample start Task A;
Task A enter sleep status;
Mempool variable sample start Task B;
this is in task b
Now Free memory number is 512B
Now Free memory number is 376B
Task B wake up Task A
Task A print the contents of the memory block;
this is an utenux programme
Task A release mpl,;
Now Free memory number is 512B
。。。。。。

【關於可變內存池使用的內存與生育內存相加不等於總內存數的問題】

我在實驗中每次申請128B,剩餘可用內存爲376B,每次申請都要損失8B內存,釋放後仍是原來的數目。後來看到這段,算是明白了:

Get memory block,'blksz' must be larger than minimum fragment size and adjusted by ROUNDSZ unit.

#define ROUNDSZ(sz)    (((UW)(sz) + (UW)(ROUNDSIZE-1)) & ~(UW)(ROUNDSIZE-1))

應該是一個內存對齊。申請121~128個block都會剩餘376B

每一個可變內存池都是一個隊列,隊列中每塊內存大小都是ROUNDSZ。申請內存的時候,只能按照ROUNDSZ大小進行分配少補多不退。。。

相關文章
相關標籤/搜索