缓冲技术之五:缓冲池的LRU管理策略C++实现
2017-11-28 17:22
891 查看
/* LRU事实上属于一类被称为内存置换算法(FIFO、LRU、LFU):都是指在有限的容量下,设计一个如何管理和更新数据项的策略 本程序是实现LRU-1算法,但是和常见的LRU算法不同,一般常规的LRU算法是直接用一个LRU双向链表队列实现管理,这种双向链 表会导致查找元素的时间复杂度位O(n),故而我的程序是在LRU双向链表的基础上附加一个map关联容器用以加速索引过程,将 查找元素的操作的时间复杂度降低为O(logN) */ #include <iostream> #include <map> //map并非hash-table #include <algorithm> #include <assert.h> #include <windows.h> //这类STL文件均没有.h后缀 using namespace std; #define BUFFER_BLOCK_SIZE 512 typedef struct __buffer_head { __buffer_head* prev; //指向前一个缓冲块 __buffer_head* next; //指向后一个缓冲块的__buffer_head int block_number;//用来标示该buffer缓冲块的全局索引号 char* buffer_content;//指向数据缓存区的指针 }buffer_head; class LRUBufferList { private: int LRUBufferList_Size_MAX; //LRU队列上限 int LRUBufferList_Size; //LRU队列当前存储量 buffer_head* LRUBufferList_First; //LRU链首 buffer_head* LRUBufferList_End; //LRU链尾 map<int, buffer_head*> quickIndex; //除了LRU管理队列外,还要配备一个额外的快速索引结构,这里采用STL提供的map public: LRUBufferList(int capacity) { LRUBufferList_Size_MAX = capacity; LRUBufferList_First = LRUBufferList_End = NULL; LRUBufferList_Size = 0; } ~LRUBufferList() { map<int, buffer_head*>::iterator iter; //清理所有的缓存块空间,释放内存 for (iter = quickIndex.begin(); iter != quickIndex.end(); iter++ ) { if (iter->second->buffer_content) //如果该缓冲块被分配了空间,则删除该空间 delete iter->second->buffer_content; delete iter->second; //删除该缓冲块的buffer_head头部结构 } quickIndex.erase(quickIndex.begin(), quickIndex.end()); //擦除map快速索引结构 LRUBufferList_First = LRUBufferList_End = NULL; //置LRU队列的管理指针为空 } //给定Block的缓冲块号,返回指定缓冲块头部指针 buffer_head* get(int param_number) { //先在map快速索引结构中定位该block块 map<int, buffer_head*>::iterator iter = quickIndex.find( param_number ); if ( iter == quickIndex.end() ) return NULL; else { //在map中找到了该缓冲块的头部指针,则意味着该缓冲块应该在LRU被提到链首 moveToHead(iter->second); return iter->second; } } //将指定的block缓冲块号中的内容替换成content指定的内容,如果LRU队列中不存在该block,则新建该block并将其加入到LRU队列中 buffer_head* rewrite(int param_number, char* content) { //如果该批次要修改的内容的有效数据内容超过511,即不能用单个缓冲块装载完,则说明是前面调度出现了问题,当然这种调度 //应该是根据具体要缓冲的内容大小而分配适当块数的缓冲块,但至于如何切割内容,显然不是由LRU队列实现的。 if ( strlen(content) > BUFFER_BLOCK_SIZE-1 ) exit(-1); map<int, buffer_head*>::iterator iter = quickIndex.find( param_number ); if (iter == quickIndex.end() ) { buffer_head* newBuffer = getFreeBuffer(param_number); strcpy(newBuffer->buffer_content, content); //新缓冲块创建成功,下面可以执行将该新Block加入到LRU队列中 addToHead(newBuffer); return newBuffer; } else //意味着LRU缓冲队列中原先便有了该缓冲块,故而需要调换该缓冲块的原先内容 { strcpy(iter->second->buffer_content, content); moveToHead(iter->second); return iter->second; } } buffer_head* getFreeBuffer(int param_number) { if (LRUBufferList_Size < LRUBufferList_Size_MAX) //在内存中创建一个新的缓冲块 { buffer_head newBuffer; newBuffer.prev = newBuffer.next = NULL; newBuffer.block_number = param_number; newBuffer.buffer_content = new char[BUFFER_BLOCK_SIZE]; //给新创建的block缓冲块分配512固定字节空间 //在快速索引结构中也添加索引 quickIndex[param_number] = &newBuffer; return &newBuffer; } else if (LRUBufferList_Size == LRUBufferList_Size_MAX) { //从LRU末尾淘汰一个对象,将其空间腾空给新的数据使用 LRUBufferList_Size--; //这里先给LRU队列中有效数据数量减1,在addToHead()操作中将加回来,逻辑更清楚 buffer_head* temp = LRUBufferList_End; LRUBufferList_End->prev->next = NULL; LRUBufferList_End = LRUBufferList_End->prev; temp->prev = temp->next = NULL; //将淘汰掉的LRU末尾缓冲块快速索引信息从map中删除掉 quickIndex.erase( temp->block_number ); temp->block_number = param_number; //在快速索引结构中修改索引 quickIndex[param_number] = temp; return temp; } } void addToHead( buffer_head* target ) { if (LRUBufferList_Size == 0) { LRUBufferList_First = LRUBufferList_End = target; } else { target->next = LRUBufferList_First; LRUBufferList_First->prev = target; LRUBufferList_First = target; } LRUBufferList_Size++; } void moveToHead( buffer_head* target ) { //如果LRU队列中只有当前target一个对象,则显然不需要再调整 if (LRUBufferList_Size == 1) return; //如果当前对象本身就是LRU队列的链首,则也无需调整 if (target == LRUBufferList_First) return; //调整target的邻居缓冲块的信息 if (target->prev) target->prev->next = target->next; if (target->next) //如果目标缓冲块的后续还有缓冲块 target->next->prev = target->prev; else //如果目标缓冲块的后续没有缓冲块,则意味着target本身就是链尾,这时移动target会牵涉到LRU队列链尾信息的变动 { if (target->prev) LRUBufferList_End = target->prev; else //如果target前向也没有缓冲块,则意味着LRU队列只有target一个 { assert( LRUBufferList_Size == 1); LRUBufferList_End = target; } } //调整目标缓冲块头部的前后缓冲块邻居信息 target->prev = NULL; target->next = LRUBufferList_First; LRUBufferList_First->prev = target; //调整LRU队列链首信息 LRUBufferList_First = target; } char* strcpy(char *dest, const char* src) { char* ret = dest; while(*src) *dest++ = *src++; *dest = '\0';//手动在字符串末尾加入\0结束符 return ret; } unsigned strlen(const char* str) { int cnt = 0; if (!str) return 0; for (; *str != '\0'; ++str) ++cnt; return cnt; } };
相关文章推荐
- InnoDB存储引擎内存缓冲池管理技术——LRU List、Free List、Flush List
- VC 绘图,使用双缓冲技术实现 2012-02-06 16:47:07 分类: C/C++
- 缓冲技术之四:LRU缓冲管理策略分析
- 内核内存池管理技术实现分析
- SmartSoft技术管理系统实现之:用C#.Net实现AutoCAD块属性提取
- c++实现简单的学生成绩管理系统
- C++ : 应用 RAII 技术在 Windows 下实现自动释放锁
- 《MFC游戏开发》笔记六 图像双缓冲技术:实现一个流畅的动画
- LRU的C++实现
- 公司技术管理角度看C++游戏程序员发展
- 设计模式C++实现(2)——策略模式
- C++实现通讯信息管理系统
- (转载)Linux内核内存池管理技术实现分析收藏
- 设计模式C++实现(2)——策略模式
- 公司技术管理角度看C++游戏程序员发展
- 使用C/C++实现内存池技术
- 常见缓存算法和LRU的c++实现
- 转:公司技术管理角度看C++游戏程序员发展
- c++ 实现顺序栈类(初始化,入栈,退栈。读栈顶元素以及顺序输出栈顶指针与栈中的元素<<计算机软件技术基础 徐士良>>
- 设计模式C++实现(2)——策略模式