缓冲技术之五:缓冲池的LRU管理策略C++实现
来源:互联网 发布:知乎live500场 百度云 编辑:程序博客网 时间:2024/06/06 10:03
/*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 512typedef 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提供的mappublic: 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; }};
阅读全文
0 0
- 缓冲技术之五:缓冲池的LRU管理策略C++实现
- 缓冲技术之四:LRU缓冲管理策略分析
- 缓冲技术之二:缓冲池BufferPool的简单实现
- 学习LFU与LRU缓冲技术的心得(举例说明)
- 《OS之缓冲技术》
- C#: GDI+双缓冲技术的使用
- win32双缓冲技术的实现
- Thread缓冲池的实现
- 缓冲策略
- Linux内核学习笔记之高速缓冲管理(五)
- 转载:缓冲池管理
- C的全缓冲、行缓冲和无缓冲
- Mysql的innodb缓冲池管理
- VS之双缓冲技术
- java之双缓冲技术
- Java之双缓冲技术
- 循环缓冲的实现
- 缓冲技术
- Mysql-索引-BTree类型 ” 的sql优化
- MySQL索引使用方法和性能优化
- 高通camera基本代码架构
- Java Web报错信息The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
- Git学习
- 缓冲技术之五:缓冲池的LRU管理策略C++实现
- Windows 7
- Filebench的安装与使用[转载]
- EmEditor Professional (文本编辑器) 官方破解版64位V17.2.5下载 | 含emeditor注册码
- replace(char oldChar, char newChar)源码分析
- Struts2(十四)---文件的上传与下载
- 自顶向下,逐步求精:从洗衣机工作程序看面向过程程序设计方法
- jQuery的each函数,类似于Java的for循环,对多个标签进行遍历
- java--(多线程创建的两种方式Thread类和Runnable接口)