模拟实现请求分页虚存页面替换

操作系统课程设计实验报告


设计题目六:模拟实现请求分页虚存页面替换

——


一、设计题目要求

(1)了解存储管理的基本目的和功能;

(2)理解实存管理的原理和实现技术;

(3)理解虚存管理的原理和实现技术;

(4)通过编程模拟实现请求分页虚存管理和替换算法。

二、程序设计思路及流程图

   程序功能简介:

  实现虚存页面替换算法的模拟程序含有以下功能:    

(1)接收用户输入的参数:程序长度(页面数)、页框个数及页面大小;

(2)程序结果采用不同的颜色区分命中、替换及直接加入空闲块;

(3)实现FIFO替换算法。

     维护两个数据结构,即请求页面队列和主存块队列。其中请求页面队列为进程所用, 记录当前进程请求的页面块信息。而主存块队列由系统维护,该队列保存当前系统 中给人主存块的状态(包括最后访问时间、忙闲状态等)。各种替换算法将以这两个 数据结构为基础,在系统中为用户请求寻求最佳块节点。

程序设计思路:

程序主要分为三大部分:

1.模拟进程访问页面:

(1)根据用户输入的进程号找到相应的页表,在该页表中查询该页号的页面是否在主存    中,若已在主存中,则直接访问,修改贮存队列中的访问时间。

(2)若不在主存队列中,则需要将其装入至主存队列,若可以找到一块空闲帧,则将其 装入至主存队列中,修改在主存中的信息:processID,pageID,state,time_last, BlockQueue中。

(3)若未在主存队列中,找到空闲帧,则需在驻留集队列中替换一个页面,替换哪一个 呢?根据FIFO算法,替换队头结点,即删除队头结点,同时将待访问页面构造为一 个新结点,插入至队尾,同时根据所删除结点的帧号在主存中队列中相应帧信息 processID,pageID,state,time_last,也要修改访问页面的信息frameID, state。

2.模拟进程结束:

     进程结束,即将此进程在内存中所占的空间释放要做3件事:

(1)从驻留集中将processID为此进程的结点删除;

(2) 主存队列中释放该进程的所有页面,即修改processID,pageID,state,time_last, 重置为初始状态;

(3)修改此进程的页表的frameID, state,置为初始状态。

3.显示部分:

(1)遍历进程的页表,打印;

(2)遍历主存队列的页表,打印;

(3)display queue,显示驻留集队列的信息。

程序流程图:

见附录A

三、涉及的背景知识及所用函数简介

1、malloc函数

函数原型 :void *malloc(unsigned int num_bytes);

头文件 :stdlib.h

作用 :分配长度为num_bytes个字节的内存块

返回值 :分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

2、asctime函数

函数原型 :char *asctime(const struct tm * timeptr);
头文件 :#include <time.h>

作用 :将时间日期以字符串格式表示参数

返回值 :若再调用相关的时间日期函数,此字符串可能会被破坏。此函数与 ctime 不同处在于传入的参数是不同的结构。

函数说明 :asctime()将参数timeptr 所指的tm 结构中的信息转换成真实世 界所使用的时间日期表示方法,然后将结果以字符串形态返回。

3、gmtime函数

函数原型 :struct tm *gmtime(const time_t *timep);

头文件 :#include <time.h>

作用 :获取当前时间和日期

函数说明 :gmtime()将参数timep 所指的time_t 结构中的信息转换成真实世 界所使用的时间日期表示方法,然后将结果由结构tm 返回。
返回值 :返回结构tm 代表目前UTC 时间。

4、strcpy 函数

函数原型 :extern char strcpy(char dest,const char src); 

头文件 :string,h

作用 :把从src地址开始且含有NULL结束符的字符串复制到已dest开始 的地址空间

参数 :scr:原串

Dest:目标串

返回值 :目标串的地址

四、程序所用数据结构简介

#define BUSY 1 

#define IDLE 0 分别定义驻留集和主存队列中的结点的状态;

#define IN 1 

#define OUT 0 分别定义页表中的结点的状态,即是否装入内存;

#define processNumber 3 提前定义好进程数目,不需要用户输入;

#define pageNumber 5 提前定义好一个进程的页面数目,不需要用户输入;

#define blockNumber 6 提前定义好主存帧数目,不需要用户输入;

#include<time.h> 时间函数需要的头文件;

typedef struct Page 

     int frameID; 

     int state; 

}Page; 定义一个页表项的信息;

 

typedef struct Block 

      int processID; 

int pageID; 

     int state; 

char time_last[50]; 

}Block; 定义一个主存队列表项的信息;

 

typedef struct process 

    Page page_table[pageNumber + 1]; 

    unsigned int pageLength; 

}process;定义一个进程的信息;

 

typedef struct node 

    int frameID; 

    int processID; 

    int pageID; 

    struct node *next; 

}BlockNode; 定义一个驻留集结点的信息;

 

typedef struct 

     BlockNode *front; 

     BlockNode *rear; 

}BlockQueue; 定义一个驻留集队列;

 

BlockQueue Q;//!!!! 全局变量,驻留集队列;

Block block_table[blockNumber + 1]; 全局变量,主存队列表;

process pro[processNumber + 1] ; 全局变量,数组存放多个进程;

int input_proID, input_pagID; 全局变量,用户输入丰进程号和页号;

 

//choose; 

void Visit_a_page();  访问一个页面;

void End_a_process(); 结束一个进程;

void Show_the_queue_information(); 显示驻留集队列中的信息;

void Show_the_block_table_information(); 显示主存队列表中的信息;

void Show_the_page_table_information_of_the_process(); 显示一个进程中的页表 的信息;

void Exit_the_system(); 退出系统;

 

void init_system(); 初始化系统;

void get_current_time(char *time_last); 获取当前时间;

int is_in_pagetable(int proID, int pagID); 判断某个进程的某页是否已装入内存;

int search_blocktable(int proID, int pagID); 在主存队列中查找某个进程的某一页;

int search_IDLE_block_in_blocktable(); 在驻留集队列中查找空闲帧;

void clear_all_process_in_blocktable(int proID); 在主存队列删除某个进程的全部 页面;

void clear_pagetable(int proID); 删除某个进程的全部页面,即清空其页表;

 

//queue; 

void init_queue(BlockQueue *Q); 初始化队列;

void enter_queue(BlockQueue *Q, BlockNode *elem); 入队;

void get_head_queue(BlockQueue *Q, BlockNode *elem); 获取对头信息;

void delete_head_queue(BlockQueue *Q, BlockNode *elem);出队; 

void delete_all_process_in_queue(BlockQueue *Q, int proID);删除一个进程在驻留 集队列中的全部页面 ;

void display_queue(BlockQueue *Q); 显示整个队列的信息;

 

五、程序源代码

见附录B

六、调试方案及调试过程记录与分析

测试结果、调试过程:

第一次测试结果:没有任何输出,显示内存信息错误。

第一次调试:在所有可能的地方加printf,测试是在哪里崩溃的,找到错误的地方,是因为没有初始化队列数据结构,另外在定义一个队列时,应该是包含有头指针和尾指针的结构体,而不是结构体指针,若是结构体指针,应该给它申请一块内存空间。当时找这个错误浪费了很长时间,还一度怀疑是自己的init_queue函数没有写对,malloc不能申请到内存。

第二次测试结果:几次修改之后,队列可以正确初始化。但是,只能插入一个结点,猜想是入队函数enter_queue没有写正确。

第二次调试:当初忘记自己写的是带头结点的队列了,在对新节点赋值是写成了Q->front,应该是Q->front->next。

第三次测试结果:enter_queue可以正确执行,随后又对delete_head_queue函数进行了验证修改,声明临时指针变量,指向被删除结点,以备释放内存使用。

第三次调试:至此,main中的case1验证完毕,然后验证case2。主要是对delete_all_process_in_queue的验证,开始以为,队列里只允许从队头删除元素,队尾插入元素, 若要从中间删除一个结点,则跟单链表的delete函数是一样的。于是便模仿着写了,但执行时,第一个结里点可以正确删除,之后的却不对,在显示队列结点的信息时,会有垃圾数字出现。后来突然明白,之前动态多分区里的链表的delete函数只是执行一次最多就删除一个,而delete_all_process_in_queue要删除多个,当删除一个节点之后,指向当前结点的指针curr所指向的结点已经没有了,curr是一个游离的指针,此时应该重新给curr赋值。

第四次测试结果:case2可以正确执行case3-6,比较简单,没有错误,程序可以正确执行。

七、思考与体会

这次实验主要是对带有头结点、包含队头队尾指针的队列数据结构的操作,受前面动态多分区链表结构的影响,也出现了一些错误,在改正这些错误的过程中,也逐渐体会到了二者的区别和用法,以及当初为什么要建立这两个模型,感觉这些前辈们真的是太聪明了。从动态多分区和请求分页替换算法(虽然只实现了FIFO)中,深深地体会到了逻辑思维严密的重要性,同时还要考虑一些特殊情况。

这学期的操作系统课程设计的六个题目,有大有小,有自己觉得写得好的,也有自己不满意的,但是都是自己亲自写的,很佩服自己能写出这么多行的代码,很佩服自己能找出错误,改正错误,同时也很讨厌自己很马虎,犯一些不该犯的错误,但是应该坚信,没有什么不可以的,一切皆有可能。还记得第一节课的时候,听到要写这么难的程序真的是头都大了,因为那些理论知识都忘了,当初学得也不好,但有些事,当硬着头皮去做的时候,收获往往很大,而且完成之后,自己也对自己很惊讶,“哇!我竟然写完了!真不可思议!”。这次课程不仅对操作系统的理论知识理解更加深刻了,而且在动手编程能力上对自己也有了信心,操作系统的一些思想让我们在以后思考问题时思维更加严谨,更有逻辑,对于解决生活中的一些问题也是有帮助的。


/************************************************************************* 
	> File Name: PageDemanding.h 
	> Author: 
	> Mail: 
	> Created Time: 2014年10月29日 星期三 15时11分10秒 
 ************************************************************************/ 
#ifndef _PAGEDEMANDING_H 
#define _PAGEDEMANDING_H 
#define BUSY 1 
#define IDLE 0 
#define IN 1 
#define OUT 0 
#define processNumber 3 
#define pageNumber 5 
#define blockNumber 6 
#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
#include<math.h> 
#include<time.h> 
typedef struct Page 
{ 
    int frameID; 
    int state; 
}Page; 
typedef struct Block 
{ 
    int processID; 
	int pageID; 
    int state; 
	char time_last[50]; 
}Block; 
typedef struct process 
{ 
    Page page_table[pageNumber + 1]; 
    unsigned int pageLength; 
}process; 
typedef struct node 
{ 
    int frameID; 
    int processID; 
    int pageID; 
    struct node *next; 
}BlockNode; 
typedef struct 
{ 
    BlockNode *front; 
    BlockNode *rear; 
}BlockQueue; 

BlockQueue Q;//!!!! 
Block block_table[blockNumber + 1]; 
process pro[processNumber + 1] ; 
int input_proID, input_pagID; 

//choose; 
void Visit_a_page();  
void End_a_process(); 
void Show_the_queue_information(); 
void Show_the_block_table_information(); 
void Show_the_page_table_information_of_the_process(); 
void Exit_the_system(); 

void init_system(); 
void get_current_time(char *time_last); 
int is_in_pagetable(int proID, int pagID); 
int search_blocktable(int proID, int pagID); 
int search_IDLE_block_in_blocktable(); 
void clear_all_process_in_blocktable(int proID); 
void clear_pagetable(int proID); 

//queue; 
void init_queue(BlockQueue *Q); 
void enter_queue(BlockQueue *Q, BlockNode *elem); 
void get_head_queue(BlockQueue *Q, BlockNode *elem); 
void delete_head_queue(BlockQueue *Q, BlockNode *elem); 
void delete_all_process_in_queue(BlockQueue *Q, int proID); 
void display_queue(BlockQueue *Q); 

#endif
/************************************************************************* 
	> File Name: main.c 
	> Author:  
	> Mail:  
	> Created Time: 2014年10月29日 星期三 15时08分08秒 
 ************************************************************************/ 

#include"PageDemanding.h" 
int main(void) 
{ 
    int choose; 
    init_system(); 
    init_queue(&Q); 
    while(1) 
    { 
        printf("\nWelcome To The DemandPagingSystem_FIFO!\n");	 
        printf("******1.Visit a page;				       ******\n");
        printf("******2.End a process;      			       ******\n"); 
	    printf("******3.Show the queue_information;		       ******\n"); 
	    printf("******4.Show the block_table_information;	       ******\n");	 
        printf("******5.Show the page_table_information of the Process;******\n"); 
	    printf("******6.Exit the system.      			       ******\n"); 
        printf("Please input your choose:\n"); 
        scanf("%d", &choose); 
        switch(choose) 
        { 
            case 1: 
            Visit_a_page();  
            break; 

            case 2: 
            End_a_process(); 
            break; 
            
            case 3: 
            Show_the_queue_information(); 
            break; 

            case 4: 
            Show_the_block_table_information(); 
            break; 
	 
            case 5: 
            Show_the_page_table_information_of_the_process(); 
            break; 

            case 6: 
            Exit_the_system(); 
            break; 
            default: 
                printf("ERROR!Please input again!\n"); 
        } 
    }//while 
    return 0; 
} 
/************************************************************************ 
	> File Name: FIFO.c 
	> Author:  
	> Mail:  
	> Created Time: 2014年10月29日 星期三 15时09分08秒 
 ************************************************************************/ 
#include"PageDemanding.h" 
void Visit_a_page() 
{ 
    int temp_blockID; 
    int i; 
    int x; 
    printf("Please input the input_proID, input_pagID:"); 
    scanf("%d%d", &input_proID, &input_pagID); 
    if(is_in_pagetable(input_proID, input_pagID)) 
    { 
        temp_blockID = search_blocktable(input_proID, input_pagID); 
        get_current_time(block_table[temp_blockID].time_last); 
    } 
    else 
    { 
        temp_blockID = search_IDLE_block_in_blocktable(); 
        if(temp_blockID != 0) 
        { 
            pro[input_proID].page_table[input_pagID].frameID = temp_blockID; 
            pro[input_proID].page_table[input_pagID].state = IN; 

            block_table[temp_blockID].processID = input_proID; 
            block_table[temp_blockID].pageID = input_pagID; 
            block_table[temp_blockID].state = BUSY; 
            get_current_time(block_table[temp_blockID].time_last); 
            
            BlockNode *create_node; 
            create_node = (BlockNode *)malloc(sizeof(BlockNode)); 
            create_node->frameID = temp_blockID; 
            create_node->processID = input_proID; 
            create_node->pageID = input_pagID; 
            create_node->next = NULL; 
            enter_queue(&Q, create_node); 
        } 
        else 
        { 
            BlockNode *elem, *p; 
            elem = (BlockNode*)malloc(sizeof(BlockNode));//** 
            p = (BlockNode *)malloc(sizeof(BlockNode));//** 
            get_head_queue(&Q, elem); 
            *p = *elem;//*** 
            p->next = NULL; 

            elem->processID = input_proID; 
            elem->pageID = input_pagID; 
            get_current_time(block_table[elem->frameID].time_last);// 
            elem->next = NULL; 
            enter_queue(&Q, elem); 

            delete_head_queue(&Q, p); 
            pro[input_proID].page_table[input_pagID].frameID = elem->frameID; 
            pro[input_proID].page_table[input_pagID].state = IN; 

            block_table[elem->frameID].processID = input_proID; 
            block_table[elem->frameID].pageID = input_pagID; 
            block_table[elem->frameID].state = BUSY; 
            get_current_time(block_table[temp_blockID].time_last); 
        }//else 
    }//else  
} 
    
void End_a_process() 
{ 
    printf("Please input the input_proID:"); 
    scanf("%d", &input_proID); 

    clear_all_process_in_blocktable(input_proID); 
    clear_pagetable(input_proID); 
    delete_all_process_in_queue(&Q, input_proID); 
    return; 
} 

void Show_the_queue_information() 
{ 
    printf("The BlockQueue information is :\n"); 
    display_queue(&Q); 
    return; 
} 
    
void Show_the_block_table_information() 
{ 
    int i; 
    printf("The block_table information:\n"); 
    printf("framID\tproID\tpagID\tstate\ttimlast\n"); 
    for(i = 1; i <= blockNumber; i++) 
    { 
        printf("%d\t%d\t%d\t%d\t%s\n", i, block_table[i].processID, block_table[i].pageID, block_table[i].state, block_table[i].time_last); 
    } 
    return ; 
} 
   
void Show_the_page_table_information_of_the_process() 
{ 
    int i; 
    printf("Please input the input_proID:"); 
    scanf("%d", &input_proID); 
    printf("\n"); 
    printf("The process %d page_table is:\n", input_proID); 
    printf("pagID\tframID\tstate\n"); 
    for(i = 1; i <= pageNumber; i++) 
    { 
        printf("%d\t%d\t%d\n", i,pro[input_proID].page_table[i].frameID, pro[input_proID].page_table[i].state); 
    } 
    return ; 
} 
void Exit_the_system() 
{ 
    exit(0); 
    return; 
} 
/*************************************************************************i 
	> File Name: PageDemanding.c 
	> Author: 
	> Mail: 
	> Created Time: 2014年10月29日 星期三 15时10分52秒 
 ************************************************************************/ 
 
#include"PageDemanding.h" 

void init_system() 
{ 
    int i, j; 
    for(i = 1; i <= blockNumber; i++)//init BlockTable; 
    { 
        block_table[i].processID = 0; 
        block_table[i].pageID = 0; 
        block_table[i].state = IDLE; 
        strcpy(block_table[i].time_last, "0000"); 
    } 
    for(i = 1; i <= processNumber; i++)//init all ProcessTable; 
    { 
        pro[i].pageLength = pageNumber; 
        for(j = 1; j <= pageNumber; j++)//init all pageTable 
        { 
            pro[i].page_table[j].frameID = 0; 
            pro[i].page_table[j].state = OUT; 
        } 
    } 
    return; 
} 
void get_current_time(char *time_last) 
{ 
    time_t timep; 
    time(&timep); 
    sprintf(time_last,"%s", asctime(gmtime(&timep))); 
    return ; 
} 
int is_in_pagetable(int proID, int pagID) 
{ 

    if(pro[proID].page_table[pagID].state == IN) 
    { 
        return 1; 
    } 
    else 
        return 0; 
} 
int search_blocktable(int proID, int pagID)//return the blockID; 
{ 
    int i; 
    for(i = 1; i <= blockNumber; i++) 
    { 
        if(block_table[i].processID == input_proID && block_table[i].pageID == pagID) 
            return i; 
    } 
    return 0; 
} 
int search_IDLE_block_in_blocktable() 
{ 
    int i; 
    for(i = 1; i <= blockNumber; i++) 
    { 
        if(block_table[i].state == IDLE) 
        { 
            return i; 
        } 
    } 
    return 0; 
} 
void clear_all_process_in_blocktable(int proID) 
{ 
    int i; 
    for(i = 1; i <= blockNumber; i++)//modify the block_table; 
    { 
        if(block_table[i].processID == proID) 
        { 
            block_table[i].processID = 0; 
            block_table[i].pageID = 0; 
            block_table[i].state = IDLE; 
            strcpy(block_table[i].time_last, "0000"); 
        } 
    } 
return ; 
} 
void clear_pagetable(int proID) 
{ 
    int i; 
    for(i = 1; i <= pageNumber; i++)//modify the page_table; 
    { 
        pro[proID].page_table[i].frameID = 0; 
        pro[proID].page_table[i].state = OUT; 
    } 
return ; 
}
/************************************************************************* 
	> File Name: queue.c 
	> Author: 
	> Mail: 
	> Created Time: 2014年10月29日 星期三 16时59分55秒 
 ************************************************************************/ 
#include"PageDemanding.h" 
//with head node queue; 
void init_queue(BlockQueue *Q) 
{ 
    Q->front = (BlockNode *)malloc(sizeof(BlockNode)); 
    Q->front->next = NULL; 
    Q->rear = Q->front; 
    return ; 
} 
void enter_queue(BlockQueue *Q, BlockNode *elem) 
{ 
    Q->rear->next = elem; 
    Q->rear = elem; 
    return ; 
} 
void get_head_queue(BlockQueue *Q, BlockNode *elem) 
{ 
    *elem = *(Q->front->next); 
    elem->next = NULL; 
    return; 
} 
void delete_head_queue(BlockQueue *Q, BlockNode *elem) 
{ 
    if(Q->front == Q->rear) 
        return ; 
    *elem = *(Q->front->next);// 
    BlockNode *item; 
    item = Q->front->next; 
    Q->front->next = item->next; 
    if(Q->rear == item) 
        Q->rear = Q->front; 
    free(item); 
    return ; 
} 
void delete_all_process_in_queue(BlockQueue *Q, int proID) 
{ 
	BlockNode *prev,*curr, *p; 
    for(curr = Q->front->next, prev = NULL; curr != NULL; prev = curr,curr = curr->next) 
    { 
        if(curr->processID == proID) 
        { 
            p = curr; 
            if(prev == NULL) 
            { 
                Q->front->next = curr->next; 
                curr = Q->front;//** 
            } 
            else if(curr == Q->rear) 
            { 
                prev->next = NULL; 
                Q->rear = prev;  //          
                return ; 
            } 
            else 
            { 
                prev->next = curr->next; 
                curr = prev;//** 
            } 
		free(p);//** 
        } 
    } 
    return; 
} 
void display_queue(BlockQueue *Q) 
{ 
    BlockNode *p; 
    p = Q->front->next; 
    if(p == NULL) 
        printf("The BlockQueue is NULL\n"); 
    else 
        printf("framID\tproID\tpagID\n"); 
    while(p) 
    { 
        printf("%d\t%d\t%d\n", p->frameID, p->processID, p->pageID); 
        p = p->next; 
    } 
    return ; 
}


 

 

你可能感兴趣的:(模拟实现请求分页虚存页面替换)