国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
內(nèi)存管理函數(shù)
我們知道,在ANSI C中可以用malloc()和free()兩個函數(shù)動態(tài)地分配內(nèi)存和釋放內(nèi)存。但是,在嵌入式實時操作系統(tǒng)中,多次這樣做會把原來很大的一塊連續(xù)內(nèi)存區(qū)域,逐漸地分割成許多非常小而且彼此又不相鄰的內(nèi)存區(qū)域,也就是內(nèi)存碎片。由于這些碎片的大量存在,使得程序到后來連非常小的內(nèi)存也分配不到。在4.02節(jié)的任務(wù)堆棧中,我們講到過用malloc()函數(shù)來分配堆棧時,曾經(jīng)討論過內(nèi)存碎片的問題。另外,由于內(nèi)存管理算法的原因,malloc()和free()函數(shù)執(zhí)行時間是不確定的。

在µC/OS-II中,操作系統(tǒng)把連續(xù)的大塊內(nèi)存按分區(qū)來管理。每個分區(qū)中包含有整數(shù)個大小相同的內(nèi)存塊,如同圖F7.1。利用這種機制,µC/OS-II 對malloc()和free()函數(shù)進行了改進,使得它們可以分配和釋放固定大小的內(nèi)存塊。這樣一來,malloc()和free()函數(shù)的執(zhí)行時間也是固定的了。

如圖 F7.2,在一個系統(tǒng)中可以有多個內(nèi)存分區(qū)。這樣,用戶的應(yīng)用程序就可以從不同的內(nèi)存分區(qū)中得到不同大小的內(nèi)存塊。但是,特定的內(nèi)存塊在釋放時必須重新放回它以前所屬于的內(nèi)存分區(qū)。顯然,采用這樣的內(nèi)存管理算法,上面的內(nèi)存碎片問題就得到了解決。

            內(nèi)存控制塊
為了便于內(nèi)存的管理,在µC/OS-II中使用內(nèi)存控制塊(memory control blocks)的數(shù)據(jù)結(jié)構(gòu)來跟蹤每一個內(nèi)存分區(qū),系統(tǒng)中的每個內(nèi)存分區(qū)都有它自己的內(nèi)存控制塊。程序清單L7.1是內(nèi)存控制塊的定義。



程序清單 L7.1 內(nèi)存控制塊的數(shù)據(jù)結(jié)構(gòu)

typedef struct {

    void   *OSMemAddr;

    void   *OSMemFreeList;

    INT32U  OSMemBlkSize;

    INT32U  OSMemNBlks;

    INT32U  OSMemNFree;

} OS_MEM;




.OSMemAddr是指向內(nèi)存分區(qū)起始地址的指針。它在建立內(nèi)存分區(qū)[見7.1節(jié),建立一個內(nèi)存分區(qū),OSMemCreate()]時被初始化,在此之后就不能更改了。

.OSMemFreeList是指向下一個空閑內(nèi)存控制塊或者下一個空閑的內(nèi)存塊的指針,具體含義要根據(jù)該內(nèi)存分區(qū)是否已經(jīng)建立來決定[見7.1節(jié)]。

.OSMemBlkSize是內(nèi)存分區(qū)中內(nèi)存塊的大小,是用戶建立該內(nèi)存分區(qū)時指定的[見7.1節(jié)]。

.OSMemNBlks是內(nèi)存分區(qū)中總的內(nèi)存塊數(shù)量,也是用戶建立該內(nèi)存分區(qū)時指定的[見7.1節(jié)]。

.OSMemNFree是內(nèi)存分區(qū)中當(dāng)前可以得空閑內(nèi)存塊數(shù)量。

如果要在µC/OS-II中使用內(nèi)存管理,需要在OS_CFG.H文件中將開關(guān)量OS_MEM_EN設(shè)置為1。這樣µC/OS-II 在啟動時就會對內(nèi)存管理器進行初始化[由OSInit()調(diào)用OSMemInit()實現(xiàn)]。該初始化主要建立一個圖 F7.3所示的內(nèi)存控制塊鏈表,其中的常數(shù)OS_MAX_MEM_PART(見文件OS_CFG.H)定義了最大的內(nèi)存分區(qū)數(shù),該常數(shù)值至少應(yīng)為2。


            建立一個內(nèi)存分區(qū),OSMemCreate()
在使用一個內(nèi)存分區(qū)之前,必須先建立該內(nèi)存分區(qū)。這個操作可以通過調(diào)用OSMemCreate()函數(shù)來完成。程序清單 L7.2說明了如何建立一個含有100個內(nèi)存塊、每個內(nèi)存塊32字節(jié)的內(nèi)存分區(qū)。



程序清單 L7.2 建立一個內(nèi)存分區(qū)

OS_MEM *CommTxBuf;

INT8U    CommTxPart[100][32];


void main (void)

{

    INT8U err;





    OSInit();

    .

    .

    CommTxBuf = OSMemCreate(CommTxPart, 100, 32, &err);

    .

    .

    OSStart();

}

程序清單 L7.3是OSMemCreate()函數(shù)的源代碼。該函數(shù)共有4個參數(shù):內(nèi)存分區(qū)的起始地址、分區(qū)內(nèi)的內(nèi)存塊總塊數(shù)、每個內(nèi)存塊的字節(jié)數(shù)和一個指向錯誤信息代碼的指針。如果OSMemCreate()操作失敗,它將返回一個NULL指針。否則,它將返回一個指向內(nèi)存控制塊的指針。對內(nèi)存管理的其它操作,象OSMemGet(),OSMemPut(),OSMemQuery()函數(shù)等,都要通過該指針進行。

每個內(nèi)存分區(qū)必須含有至少兩個內(nèi)存塊[L7.3(1)],每個內(nèi)存塊至少為一個指針的大小,因為同一分區(qū)中的所有空閑內(nèi)存塊是由指針串聯(lián)起來的[L7.3(2)]。接著,OSMemCreate()從系統(tǒng)中的空閑內(nèi)存控制塊中取得一個內(nèi)存控制塊[L7.3(3)],該內(nèi)存控制塊包含相應(yīng)內(nèi)存分區(qū)的運行信息。OSMemCreate()必須在有空閑內(nèi)存控制塊可用的情況下才能建立一個內(nèi)存分區(qū)[L7.3(4)]。在上述條件均得到滿足時,所要建立的內(nèi)存分區(qū)內(nèi)的所有內(nèi)存塊被鏈接成一個單向的鏈表[L7.3(5)]。然后,在對應(yīng)的內(nèi)存控制塊中填寫相應(yīng)的信息[L7.3(6)]。完成上述各動作后,OSMemCreate()返回指向該內(nèi)存塊的指針。該指針在以后對內(nèi)存塊的操作中使用[L7.3(6)]。


OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)

{

    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);

    }

    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)

}

            分配一個內(nèi)存塊,OSMemGet()
應(yīng)用程序可以調(diào)用OSMemGet()函數(shù)從已經(jīng)建立的內(nèi)存分區(qū)中申請一個內(nèi)存塊。該函數(shù)的唯一參數(shù)是指向特定內(nèi)存分區(qū)的指針,該指針在建立內(nèi)存分區(qū)時,由OSMemCreate()函數(shù)返回。顯然,應(yīng)用程序必須知道內(nèi)存塊的大小,并且在使用時不能超過該容量。例如,如果一個內(nèi)存分區(qū)內(nèi)的內(nèi)存塊為32字節(jié),那么,應(yīng)用程序最多只能使用該內(nèi)存塊中的32字節(jié)。當(dāng)應(yīng)用程序不再使用這個內(nèi)存塊后,必須及時把它釋放,重新放入相應(yīng)的內(nèi)存分區(qū)中[見7.03節(jié),釋放一個內(nèi)存塊,OSMemPut()]。

程序清單 L7.4是OSMemGet()函數(shù)的源代碼。參數(shù)中的指針pmem指向用戶希望從其中分配內(nèi)存塊的內(nèi)存分區(qū)[L7.4(1)]。OSMemGet()首先檢查內(nèi)存分區(qū)中是否有空閑的內(nèi)存塊[L7.4(2)]。如果有,從空閑內(nèi)存塊鏈表中刪除第一個內(nèi)存塊[L7.4(3)],并對空閑內(nèi)存塊鏈表作相應(yīng)的修改 [L7.4(4)]。這包括將鏈表頭指針后移一個元素和空閑內(nèi)存塊數(shù)減1[L7.4(5)]。最后,返回指向被分配內(nèi)存塊的指針[L7.4(6)]。


void *OSMemGet (OS_MEM *pmem, INT8U *err)                              (1)

{

    void    *pblk;





    OS_ENTER_CRITICAL();

    if (pmem->OSMemNFree > 0) {                                        (2)

        pblk                = pmem->OSMemFreeList;                     (3)

        pmem->OSMemFreeList = *(void **)pblk;                          (4)

        pmem->OSMemNFree--;                                            (5)

        OS_EXIT_CRITICAL();

        *err = OS_NO_ERR;

        return (pblk);                                                 (6)

    } else {

        OS_EXIT_CRITICAL();

        *err = OS_MEM_NO_FREE_BLKS;

        return ((void *)0);

    }

}

值得注意的是,用戶可以在中斷服務(wù)子程序中調(diào)用OSMemGet(),因為在暫時沒有內(nèi)存塊可用的情況下,OSMemGet()不會等待,而是馬上返回NULL指針。



            釋放一個內(nèi)存塊,OSMemPut()
當(dāng)用戶應(yīng)用程序不再使用一個內(nèi)存塊時,必須及時地把它釋放并放回到相應(yīng)的內(nèi)存分區(qū)中。這個操作由OSMemPut()函數(shù)完成。必須注意的是,OSMemPut()并不知道一個內(nèi)存塊是屬于哪個內(nèi)存分區(qū)的。例如,用戶任務(wù)從一個包含32字節(jié)內(nèi)存塊的分區(qū)中分配了一個內(nèi)存塊,用完后,把它返還給了一個包含120字節(jié)內(nèi)存塊的內(nèi)存分區(qū)。當(dāng)用戶應(yīng)用程序下一次申請120字節(jié)分區(qū)中的一個內(nèi)存塊時,它會只得到32字節(jié)的可用空間,其它88字節(jié)屬于其它的任務(wù),這就有可能使系統(tǒng)崩潰。

程序清單 L7.5是OSMemPut()函數(shù)的源代碼。它的第一個參數(shù)pmem是指向內(nèi)存控制塊的指針,也即內(nèi)存塊屬于的內(nèi)存分區(qū)[L7.5(1)]。OSMemPut()首先檢查內(nèi)存分區(qū)是否已滿[L7.5(2)]。如果已滿,說明系統(tǒng)在分配和釋放內(nèi)存時出現(xiàn)了錯誤。如果未滿,要釋放的內(nèi)存塊被插入到該分區(qū)的空閑內(nèi)存塊鏈表中[L7.5(3)]。最后,將分區(qū)中空閑內(nèi)存塊總數(shù)加1[L7.5(4)]。

INT8U OSMemPut (OS_MEM  *pmem, void *pblk)                             (1)

{

    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)

    OS_EXIT_CRITICAL();

    return (OS_NO_ERR);

}




            查詢一個內(nèi)存分區(qū)的狀態(tài),OSMemQuery()
在µC/OS-II 中,可以使用OSMemQuery()函數(shù)來查詢一個特定內(nèi)存分區(qū)的有關(guān)消息。通過該函數(shù)可以知道特定內(nèi)存分區(qū)中內(nèi)存塊的大小、可用內(nèi)存塊數(shù)和正在使用的內(nèi)存塊數(shù)等信息。所有這些信息都放在一個叫OS_MEM_DATA的數(shù)據(jù)結(jié)構(gòu)中,如程序清單 L7.6。

typedef struct {

    void  *OSAddr;     /* 指向內(nèi)存分區(qū)首地址的指針 */

    void  *OSFreeList; /* 指向空閑內(nèi)存塊鏈表首地址的指針 */

    INT32U OSBlkSize;  /* 每個內(nèi)存塊所含的字節(jié)數(shù) */

    INT32U OSNBlks;    /* 內(nèi)存分區(qū)總的內(nèi)存塊數(shù) */

    INT32U OSNFree;    /* 空閑內(nèi)存塊總數(shù) */

    INT32U OSNUsed;    /* 正在使用的內(nèi)存塊總數(shù) */

} OS_MEM_DATA;

程序清單 L7.7是OSMemQuery()函數(shù)的源代碼,它將指定內(nèi)存分區(qū)的信息復(fù)制到OS_MEM_DATA定義的變量的對應(yīng)域中。在此之前,代碼首先禁止了外部中斷,防止復(fù)制過程中某些變量值被修改[L7.7(1)]。由于正在使用的內(nèi)存塊數(shù)是由OS_MEM_DATA中的局部變量計算得到的,所以,可以放在(critical section中斷屏蔽)的外面。

INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *pdata)

{

    OS_ENTER_CRITICAL();

    pdata->OSAddr     = pmem->OSMemAddr;                               (1)

    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)

    return (OS_NO_ERR);

}


            Using Memory Partitions

第一個任務(wù)讀取并檢查模擬輸入量的值(如氣壓、溫度、電壓等),如果其超過了一定的閾值,就向第二個任務(wù)發(fā)送一個消息。該消息中含有時間信息、出錯的通道號和錯誤代碼等可以想象的任何可能的信息。

錯誤處理程序是該例子的中心。任何任務(wù)、中斷服務(wù)子程序都可以向該任務(wù)發(fā)送出錯消息。錯誤處理程序則負(fù)責(zé)在顯示設(shè)備上顯示出錯信息,在磁盤上登記出錯記錄,或者啟動另一個任務(wù)對錯誤進行糾正等。


程序清單 L7.8 內(nèi)存分配的例子——掃描模擬量的輸入和報告出錯

AnalogInputTask()

{

    for (;;) {

        for (所有的模擬量都有輸入) {

            讀入模擬量輸入值;                                           (1)

            if (模擬量超過閾值) {

                得到一個內(nèi)存塊;                                        (2)

                得到當(dāng)前系統(tǒng)時間 (以時鐘節(jié)拍為單位);                   (3)

                將下列各項存入內(nèi)存塊:                                  (4)

                    系統(tǒng)時間 (時間戳);

                    超過閾值的通道號;

                    錯誤代碼;

                    錯誤等級;

                    等.

                向錯誤隊列發(fā)送錯誤消息;                                (5)

                    (一個指向包含上述各項的內(nèi)存塊的指針)

            }

        }

        延時任務(wù),直到要再次對模擬量進行采樣時為止;

    }

}







ErrorHandlerTask()

{

    for (;;) {

        等待錯誤隊列的消息;                                            (6)

            (得到指向包含有關(guān)錯誤數(shù)據(jù)的內(nèi)存塊的指針)

        讀入消息,并根據(jù)消息的內(nèi)容執(zhí)行相應(yīng)的操作;                       (7)

        將內(nèi)存塊放回到相應(yīng)的內(nèi)存分區(qū)中;                                (8)

    }

}




            等待一個內(nèi)存塊
有時候,在內(nèi)存分區(qū)暫時沒有可用的空閑內(nèi)存塊的情況下,讓一個申請內(nèi)存塊的任務(wù)等待也是有用的。但是,µC/OS-II本身在內(nèi)存管理上并不支持這項功能。如果確實需要,則可以通過為特定內(nèi)存分區(qū)增加信號量的方法,實現(xiàn)這種功能(見6.05節(jié),信號量)。應(yīng)用程序為了申請分配內(nèi)存塊,首先要得到一個相應(yīng)的信號量,然后才能調(diào)用OSMemGet()函數(shù)。
程序代碼首先定義了程序中使用到的各個變量[L7.9(1)]。該例中,直接使用數(shù)字定義了各個變量的大小,實際應(yīng)用中,建議將這些數(shù)字定義成常數(shù)。在系統(tǒng)復(fù)位時,µC/OS-II調(diào)用OSInit()進行系統(tǒng)初始化[L7.9(2)],然后用內(nèi)存分區(qū)中總的內(nèi)存塊數(shù)來初始化一個信號量[L7.9(3)],緊接著建立內(nèi)存分區(qū)[L7.9(4)]和相應(yīng)的要訪問該分區(qū)的任務(wù)[L7.9(5)]。當(dāng)然,到此為止,我們對如何增加其它的任務(wù)也已經(jīng)很清楚了。顯然,如果系統(tǒng)中只有一個任務(wù)使用動態(tài)內(nèi)存塊,就沒有必要使用信號量了。這種情況不需要保證內(nèi)存資源的互斥。事實上,除非我們要實現(xiàn)多任務(wù)共享內(nèi)存,否則連內(nèi)存分區(qū)都不需要。多任務(wù)執(zhí)行從OSStart()開始[L7.9(6)]。當(dāng)一個任務(wù)運行時,只有在信號量有效時[L7.9(7)],才有可能得到內(nèi)存塊[L7.9(8)]。一旦信號量有效了,就可以申請內(nèi)存塊并使用它,而沒有必要對OSSemPend()返回的錯誤代碼進行檢查。因為在這里,只有當(dāng)一個內(nèi)存塊被其它任務(wù)釋放并放回到內(nèi)存分區(qū)后,µC/OS-II才會返回到該任務(wù)去執(zhí)行。同理,對OSMemGet()返回的錯誤代碼也無需做進一步的檢查(一個任務(wù)能得以繼續(xù)執(zhí)行,則內(nèi)存分區(qū)中至少有一個內(nèi)存塊是可用的)。當(dāng)一個任務(wù)不再使用某內(nèi)存塊時,只需簡單地將它釋放并返還到內(nèi)存分區(qū)[L7.9(9)],并發(fā)送該信號量
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
ucos II 內(nèi)核學(xué)習(xí)之七:內(nèi)存管理
UC/OS-II的內(nèi)存管理OSMemCreate()分析
uC/OS-II的內(nèi)存管理
啟動ucosii之一OSInit()
uc/os—II下的九個C語言文件功能函數(shù)大全(二)
uCOS
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服