参考书籍:《Linux操作系统实验教材》——主编:费翔林
FIFO 、 LRU 、OPT
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<sys/time.h>
#include<unistd.h>
#define BUSY 1
#define IDLE 0
#define blockNumber 3
#define n 10
int Time = 0;
typedef struct _Page{ // 页面
int pageID; //页号
}Page;
typedef struct _PageQueue{ //页面队列
Page page;
struct _PageQueue* next; //下一页面
}PageQueue;
typedef struct _Block{ //块记录结构
Page *page; //页面
long time; //最后访问时间
int state; //页块是否空闲
}Block;
typedef struct _BlockQueue{ //块队列
Block block;
struct _BlockQueue *next;
}BlockQueue;
typedef struct process{ // 进程结构
PageQueue pages; //页面
unsigned int pageLength; // 页面数
}process;//进程
//初始化主存块,把首地址返回,如果分配失败返回NULL
BlockQueue* InitializeBlockQueue(unsigned int size){
BlockQueue *p1, *p2;
BlockQueue *block;
block = NULL;
int i;
for(i = 0; i < size; ++i){
p1 = (BlockQueue*)malloc(sizeof(BlockQueue));
p1->block.time = 0;
p1->block.state = 0;
p1->block.page = NULL;
p1->next = NULL;
if(block == NULL) block = p1;
else p2->next = p1;
p2 = p1;
}
return block;
}
//获取块长度
int GetBlockQueueSize(BlockQueue *blockQueue){
BlockQueue *presentBlock;
presentBlock = blockQueue;
int blockQueueSize = 0;
while(presentBlock != NULL){
blockQueueSize++;
presentBlock = presentBlock->next;
}
return blockQueueSize;
}
//清空块内容
void ResetBlockQueue(BlockQueue *blockQueue){
BlockQueue *presentBlock;
presentBlock = blockQueue;
while(presentBlock != NULL){
presentBlock->block.page = NULL;
presentBlock->block.state = IDLE;
presentBlock->block.time = 0;
presentBlock = presentBlock->next;
}
}
//打印块信息
void PrintBlockList(BlockQueue *blockQueue, int pageID, int color){
BlockQueue *presentBlock;
char strl[5], *str2;
presentBlock = blockQueue;
while(presentBlock != NULL){
if(presentBlock->block.state == IDLE)
printf("| |\n");
else{
printf("| %d |\n", presentBlock->block.page->pageID);
}
presentBlock = presentBlock->next;
}
printf("\n");
}
//初始化页面
PageQueue* InitializePageQueue(unsigned int pageLength, int maxPageID){
srand((unsigned)time(NULL)); // 随机数种子
// srand(101); // 伪随机,用于调试
PageQueue *head;
head = NULL;
PageQueue *p, *q;
int i;
for(i = 0; i < pageLength; ++i){
p = (PageQueue*)malloc(sizeof(PageQueue));
p->page.pageID = (int)(rand() % (maxPageID));
printf("%d ", p->page.pageID);
p->next = NULL;
if(head == NULL) head = p;
else q->next = p;
q = p;
}
printf("\n");
return head;
}
//初始化进程
void InitializeProcess(process *proc, unsigned int pageSize, unsigned int maxPageID){
printf("进程初始化:\n");
proc->pageLength = pageSize;
proc->pages.next = InitializePageQueue(pageSize, maxPageID);
}
//搜索特定页面
BlockQueue* SearchPage(BlockQueue *blockQueue, Page page){
BlockQueue *p;
int blockSize;
p = blockQueue;
while(p != NULL){
if(p->block.page != NULL){
if(p->block.page->pageID == page.pageID)
return p;
}
}
return NULL;
}
//搜索空闲块
BlockQueue* SearchIdleBlock(BlockQueue *blockQueue){
BlockQueue *p;
p = blockQueue;
while(p != NULL){
if(p->block.state == IDLE)
return p;
else p = p->next;
}
return NULL;
}
//取得主存中停留最久的页面,返回它的地址
BlockQueue* GetOldestBlock(BlockQueue *blockQueue){
BlockQueue *p;
p = blockQueue;
BlockQueue *q; // 辅助标记最小time的block的指针
q = p;
if (p->next != NULL){
while(p->next!=NULL){ //轮循 比较,求最小的time的block并返回
if (q->block.time > p->next->block.time){
q = p->next;
};
p = p->next;
};
return q;
}else {
return p;
}
}
// 取得最近最久未使用的Block,原理与 GetOldestBlock相同
// 查找time最小的 time的block
// 不同的处理再LRU函数中可见
BlockQueue* GetLastestNoUseBlock(BlockQueue *blockQueue){
return GetOldestBlock(blockQueue);
}
BlockQueue* GetLongTimeNoUseBlock(BlockQueue *blockQueue, PageQueue *cur, int Time){
BlockQueue *p;
p = blockQueue;
PageQueue *c;
c = cur;
BlockQueue *q; // 辅助标记要返回的block的指针,time=0则立即返回,否则返回time最大的。
q = p;
int ti = Time;
while(p != NULL) {
while(c!= NULL){
ti++;
if (p->block.page->pageID == c->page.pageID){
p->block.time = ti;
break;
}
c = c->next;
};
ti = Time; // 恢复
p = p->next;
};
p = q;
if (p->next != NULL){
while(p->next!=NULL){ //轮循 比较,求time为0, 若无为0则求最大的time的block并返回
if (p->block.time == 0){
return p;
}
if (q->block.time < p->next->block.time){
q = p->next;
};
p = p->next;
};
return q;
}else {
return p;
}
}
//先进先出算法
void FIFO(BlockQueue *blockQueue, process *proc){
int blockQueueSize = GetBlockQueueSize(blockQueue);
PageQueue *currentPage;
currentPage = proc->pages.next;
BlockQueue *p;
p = blockQueue;
int count = 0, cnt = 0;
Time = 0;
printf("\nFIFO算法:\n");
while(currentPage != NULL){
int ok = 0;
p = blockQueue;
Time++; // 用于辅助 记录每个块的page进入的时间
while(p != NULL){ // 判断当前页面是否已在块(内存)中
if(p->block.page !=NULL && p->block.page->pageID == currentPage->page.pageID){
ok = 1;
break;
}
p = p->next;
}
if(ok){ // 若当前页面已在内存中
PrintBlockList(blockQueue, currentPage->page.pageID, 0);
}
else{ // 若当前页面不在内存中 ,调度
BlockQueue *block;
block = SearchIdleBlock(blockQueue);
if(block != NULL){ // 内存中有空闲块,不需要把已有的块置换出去
block->block.state = BUSY;
block->block.time = Time;
block->block.page = (Page*)malloc(sizeof(Page));
block->block.page->pageID = currentPage->page.pageID;
PrintBlockList(blockQueue, currentPage->page.pageID, 1);
}
else{ // 内存没有空闲块
BlockQueue *block;
block = GetOldestBlock(blockQueue); // 获得块队列中最先进入的块
block->block.time = Time;
block->block.page->pageID = currentPage->page.pageID;
PrintBlockList(blockQueue, currentPage->page.pageID, 2);
};
count++;
}
currentPage = currentPage->next;
cnt++;
}
printf("FIFO\n缺页次数 = %d\n总数 = %d\n缺页率 = %.4lf", count, cnt, (double)count/(double)cnt);
}
// 最近最少使用算法
void LRU(BlockQueue *blockQueue, process *proc){
int blockQueueSize = GetBlockQueueSize(blockQueue);
PageQueue *currentPage;
currentPage = proc->pages.next;
BlockQueue *p;
p = blockQueue;
int count = 0, cnt = 0;
Time = 0;
printf("\nLRU算法:\n");
while(currentPage != NULL){
int ok = 0;
p = blockQueue;
Time++; // 用于辅助 记录每个块的page进入的时间
while(p != NULL){ // 判断当前页面是否已在块(内存)中
if(p->block.page !=NULL && p->block.page->pageID == currentPage->page.pageID){
// 与FIFO的唯一区别:即使没有调度,但是有使用,需要更新time
p->block.time = Time;
ok = 1;
break;
}
p = p->next;
}
if(ok){ // 若当前页面已在内存中
PrintBlockList(blockQueue, currentPage->page.pageID, 0);
}
else{ // 若当前页面不在内存中 ,调度
BlockQueue *block;
block = SearchIdleBlock(blockQueue);
if(block != NULL){ // 内存中有空闲块,不需要把已有的块置换出去
block->block.state = BUSY;
block->block.time = Time;
block->block.page = (Page*)malloc(sizeof(Page));
block->block.page->pageID = currentPage->page.pageID;
PrintBlockList(blockQueue, currentPage->page.pageID, 1);
}
else{ // 内存没有空闲块
BlockQueue *block;
block = GetLastestNoUseBlock(blockQueue); // 获得块队列中最近未使用的block
block->block.time = Time;
block->block.page->pageID = currentPage->page.pageID;
PrintBlockList(blockQueue, currentPage->page.pageID, 2);
};
count++;
}
currentPage = currentPage->next;
cnt++;
}
printf("LRU\n缺页次数 = %d\n总数 = %d\n缺页率 = %.4lf", count, cnt, (double)count/(double)cnt);
}
// 最佳算法,理想状态
// block.time不再用来记录最后进入时间,而用来记录未来最先到达之间,未来不出现为0
void OPT(BlockQueue *blockQueue, process *proc){
int blockQueueSize = GetBlockQueueSize(blockQueue);
PageQueue *currentPage;
currentPage = proc->pages.next;
BlockQueue *p;
p = blockQueue;
int count = 0, cnt = 0;
Time = 0; // 初始化
printf("\nOPT算法:\n");
while(currentPage != NULL){
int ok = 0;
p = blockQueue;
Time++; // 用于辅助 记录每个块的page进入的时间
while(p != NULL){ // 判断当前页面是否已在块(内存)中
if(p->block.page !=NULL && p->block.page->pageID == currentPage->page.pageID){
ok = 1;
break;
}
p = p->next;
}
if(ok){ // 若当前页面已在内存中
PrintBlockList(blockQueue, currentPage->page.pageID, 0);
}
else{ // 若当前页面不在内存中 ,调度
BlockQueue *block;
block = SearchIdleBlock(blockQueue);
if(block != NULL){ // 内存中有空闲块,不需要把已有的块置换出去
block->block.state = BUSY;
block->block.time = 0;
block->block.page = (Page*)malloc(sizeof(Page));
block->block.page->pageID = currentPage->page.pageID;
PrintBlockList(blockQueue, currentPage->page.pageID, 1);
}
else{ // 内存没有空闲块,需要把已有的块置换出去
BlockQueue *block;
block = GetLongTimeNoUseBlock(blockQueue, currentPage, Time); // 获得未来最久未使用或不使用的page对应的block
block->block.time = 0;
block->block.page->pageID = currentPage->page.pageID;
PrintBlockList(blockQueue, currentPage->page.pageID, 2);
};
count++;
}
currentPage = currentPage->next;
cnt++;
}
printf("OPT\n缺页次数 = %d\n总数 = %d\n缺页率 = %.4lf", count, cnt, (double)count/(double)cnt);
}
int main(){
int pageNumber;
printf("输入page number = \n");
scanf("%d", &pageNumber);
printf("Block Number : %d, Page Number : %d\n\n", blockNumber, pageNumber);
BlockQueue *blocks;
process proc;
InitializeProcess(&proc, pageNumber, n);
blocks = InitializeBlockQueue(blockNumber);
printf("\n--------------------\n");
// FIFO算法
FIFO(blocks, &proc);
ResetBlockQueue(blocks);
printf("\n--------------------\n");
// LRU算法
LRU(blocks, &proc);
ResetBlockQueue(blocks);
printf("\n--------------------\n");
// OPT算法
OPT(blocks, &proc);
ResetBlockQueue(blocks);
return 0;
}
贴效果图:
建议理解自己敲,并没想象中那么难。