組み込みのオペレーティングシステムなしでのメモリとキューの管理(UCOS IIの考えのように)

例:最大128エントリ、それぞれ最大1MBのログを保存します。

メモリの側面組み込みは動的メモリには適していないため、断片化が発生します。ここでは、u8 data [LOG_SIZE];を使用して固定の128MBメモリ領域を開き、管理のために128個の1MBメモリブロックに分割します。
管理方法は、メモリ制御ブロック構造MCBを使用し、加算、削除、変更機能を書き込んでMCBを操作して管理する方法です。

キューに関しては、循環キューを使用します。たとえば、キュ​​ーには最大10個の要素があります。11番目の要素を格納すると、最初の要素が上書きされます。
管理方法は次のとおりです。キュー制御ブロック構造LoopQueueを使用してから、追加、削除、および変更関数を記述して、管理のためにLoopQueueを操作します。

メモリブロックとキューの関連付けは、
情報が格納されるメモリブロック1)や(キュー位置1)
などのポインタに基づいています①メモリブロック1のアドレスポインタをキュー位置1に
格納できます; ②定義することもできます新しい構造本文には、メモリブロック1のアドレスポインタ、メッセージのシリアル番号、およびメッセージの時刻が含まれています。次に、この構造体のポインタをキュー位置1に格納します。

1.128MBのメモリを管理する

#define LOG_SIZE 0x8000000  //  (0x8000000 / 1024 / 1024= 128)
#define Blk_Num 128

//内存控制块结构体 Memory control block
typedef struct _MCB {
    
    
    void*   BeginAddr;  //指向开辟的内存的首地址
    uint32  TotalSize;  //开辟内存的总大小
    uint32  BlkSize;    //每个内存块的大小
    uint32  BlkNums;    //开辟的总内存块数目
    uint32  FreeBlks;   //可用的内存块数目
    uint32  BlkOut;     //获取内存时释放的位置
    uint32  BlkIn;      //回收内存时存放的位置
    uint32  MemAddr[Blk_Num];//该数组存储所有内存块的首地址
} MCB;

//对指定内存的实际操作就靠这两个全局变量
u8 data[LOG_SIZE];
MCB LogMCB;

//初始化,应该用函数执行,这里简单贴出来:
memset(data,0,sizeof(u8)*LOG_SIZE);

LogMCB.BeginAddr = data;
LogMCB.TotalSize = 0x8000000*sizeof(u8); //128MB
LogMCB.BlkSize   = 0x100000*sizeof(u8);  //1MB
LogMCB.BlkNums   = LogMCB.TotalSize/LogMCB.BlkSize;
LogMCB.FreeBlks  = LogMCB.BlkNums;
LogMCB.BlkIn     = 0;
LogMCB.BlkOut    = 0;
For(i=0;i<LogMCB.BlkNums;i++)
{
    
    
    LogMCB.MemAddr[i] = LogMCB.BeginAddr+(i*LogMCB.BlkSize);
}

//获取一块内存时各变量对应的操作:
LogMCB.MemAddr[LogMemObj.BlkOut] = 0; 置零
LogMCB.BeginAddr;   不变
LogMCB.TotalSize;   不变
LogMCB.BlkSize;     不变
LogMCB.BlkNums;     不变
LogMCB.FreeBlks--;  减一
LogMCB.BlkOut++;    加一
LogMCB.BlkIn;       不变

//释放一块内存时各变量对应的操作:
LogMCB.MemAddr[LogMemObj.BlkIn]  = addr;  赋值
LogMCB.BeginAddr;   不变
LogMCB.TotalSize;   不变
LogMCB.BlkSize;     不变
LogMCB.BlkNums;     不变
LogMCB.FreeBlks++;  加一
LogMCB.BlkOut;      不变
LogMCB.BlkIn++;     加一


コードは機能解析です。実際の使用では、メモリの初期化、メモリの取得、メモリの解放を関数としてパッケージ化する必要があります。

ここに画像の説明を挿入
//メモリ制御構造
の各メンバーの意味と使用法を理解するにはtypedefstruct _MCB { void * BeginAddr; //開いているメモリの最初のアドレスを指すuint32TotalSize; //開いているメモリの合計サイズuint32BlkSize; / /各メモリブロックのサイズuint32BlkNums; //開かれたメモリブロックの総数uint32FreeBlks; //使用可能なメモリブロックの数uint32BlkOut; //メモリが取得されたときに解放される場所uint32BlkIn; //メモリが格納されている場所uint32MemAddr [Blk_Num]; //この配列は、すべてのメモリブロックの最初のアドレスを格納します} MCB;








//指定されたメモリの実際の動作は、これら2つのグローバル変数に依存します
u8 data [LOG_SIZE];
MCB LogMCB;

第2に、循環キュー管理ログで
は、ログが操作を送受信する必要がある場合、実際のキューは50のみで、ログのトランシーバー128に対応できます。したがって、キューの数はメモリブロックの数ほど多くする必要はありません。

#define MAX 128
typedef struct _LoopQueue 
{
    
    
    uint32    QueueMax;     //队列最大数目
    uint32    QueueUsed;    //使用了的数目
    uint32    QueueIn;      //进队位置
    uint32    QueueOut;     //出队位置
    void      *Member[MAX]; //存储每条日志的结构体指针
} LoopQueue;

LoopQueue LogQueue;

//initial
LogQueue.QueueMax  = MAX;
LogQueue.QueueUsed = 0;
LogQueue.QueueIn   = 0;
LogQueue.QueueOut  = 0;
for(int i=0;i<MAX;i++)
{
    
    
    LogQueue.Member[i] = NULL;
}

//存储一条日志到内存块后,将内存块地址存入队列。我们发送日志时 直接操作队列、间接操作内存块:
void *nowlog = LogMCB.MemAddr[LogMemObj.BlkOut] ;
LogMCB.MemAddr[LogMCB.FreeRingOut]  = 0;
LogMCB.FreeBlks--;  
LogMCB.BlkOut++;    

LogQueue.Member[LogQueue.QueueIn]  =  (void *)nowlog ;
LogQueue.QueueUsed ++;
LogQueue.QueueIn   ++;

//删除一条日志时:
LOG * nlog = (LOG *)LogQueue.Member[LogQueue.QueueOut]  ;
LogQueue.Member[LogQueue.QueueOut] = NULL;
LogQueue.QueueOut ++;
LogQueue.QueueUsed --;

LogMCB.MemAddr[LogMCB.BlkIn]  = (void *)nlog;  
LogMCB.FreeBlks++;  
LogMCB.BlkIn++;     

//队列实现循环:
LogQueue.QueueIn  = LogQueue.QueueIn % LogQueue.QueueMax ;  //比如存第129条,会存储到物理第一条的位置
LogQueue.QueueOut = LogQueue.QueueOut  % LogQueue.QueueMax ; 

ここに画像の説明を挿入
より重要なものは、メモリの初期化、メモリの使用量、メモリの回復、キューの初期化、キューの使用量、およびキューの回復です。ポインタは、ログの実際の割り当て以外の多くの場所での対話に使用されます。

主にログの保存と削除の際の理解:メモリ管理とキュー管理:
//ログの保存時:
// 1、メモリブロックを使用
void * nowlog = LogMCB.MemAddr [LogMCB.BlkOut];
LogMCB.MemAddr [LogMCB.FreeRingOut ] = 0;
LogMCB.FreeBlks–;
LogMCB.BlkOut ++;

// 2、アドレスにログを書き込みます(必ずしもこのメソッドを使用する必要はありません)
memcpy(nowlog、pdata、0x100000 * sizeof(u8));

// 3、ログポインタをキュー
LogQueue.Member [LogQueue.QueueIn]に格納します=(void )nowlog;
LogQueue.QueueUsed ++;
LogQueue.QueueIn ++;

//ログを削除する場合:

// 1、キュー内のログポインタを取り出します
void
nowlog =(LOG *)LogQueue.Member [LogQueue。 QueueOut];
LogQueue.Member [LogQueue.QueueOut] = NULL;
LogQueue.QueueOut ++;
LogQueue.QueueUsed-;
// 2、ログポインタはメモリブロックの最初のアドレスのポインタでもあり、メモリブロックを再利用します
LogMCB.MemAddr [LogMCB.BlkIn] =(void *)nlog;
LogMCB.FreeBlks ++;
LogMCB.BlkIn ++;

//キュー実装ループ:

LogQueue.QueueIn = LogQueue.QueueIn%LogQueue.QueueMax;
//たとえば、129番目のアイテムを保存すると、最初の物理的な場所に保存されます
LogQueue.QueueOut = LogQueue.QueueOut%LogQueue.QueueMax;

おすすめ

転載: blog.csdn.net/LIU944602965/article/details/103277573