当前位置:文档之家› 操作系统实验二——cpu调度与内存分页

操作系统实验二——cpu调度与内存分页

这里的Run函数其实模拟了CPU的取指令和翻译指令的功能,本程序只有一个有实际作用的指令,'O',如果内存中的内容为'0'(十进制ASCⅡ码值),则代表需要利用I/O设备输出该地址内容。如上图所示,PCB会加入O设备是否开启,如果未开启则开启设备。Run函数也因此返回一个interrupt值。
<< "***************************" << endl ;
return -1 ;
}
void PCB::printPageTable()
{
outfile.open("PageTable.txt", ios_base::app) ;
outfile << "***************************"
<< " PCB p" << number << " "
代码:
#include<iostream>
#include<list>
#include<queue>
#include<iterator>
#include<windows.h>
#include<fstream>
#include<cstdlib>
#include<ctime>
using namespace std ;
第二点缺陷是,没有按照题目要求分配那么多的内存空间,因为那么大输入输出不好控制。
在本程序中,输入输出与要求有出入,并没有输入进程需要的时间,而是以进程的具体内容代替,在这里又有一个假设:假设进程在CPU中每执行一步需要一个单位的时间,这样进程的大小也就等价于进程需要的时间了(排除有I/O请求的情况),个人认为这样假设比人工限定执行时间更加贴近现实情况。
@param1要找的页号
@return如果失败,返回-1.成功则返回帧号
**/
int findframe(const int& page) ;
/*打印页表*/
void printPageTable() ;
/* I/O状态信息*/
//
/*构造函数*/
PCB(const Program& p) ;
};
int PCB::findframe(const int& page)
#define TERMINATED 4
/*运行状态*/
#define INTERRUPT 2 //中断
#define NORMAL 1 //正常
#define ERROR 0 //出错
#define FINISH 1 //完成
/*时间片大小*/
#define TimeSlice 1
/*设备信息*/
int process_number ;
/*被该进程的哪一页占用*/
int page_number ;
FrameTableNode()
{
free = true ;
}
};
class FrameTable
{
public:
/*帧表*/
FrameTableNode frametable[MEMORY] ;
/*当前可用的帧的数目*/
五、心得体会
为了很好的仿真,本次试验尽可能地模拟了硬件的工作,,如输入输出设备和模拟CPU的run函数,基本上把教材77页调度问题的队列图所示功能模拟出来了,也大体实现了从用户程序到系统进程再到硬件的执行过程。
对于本次实验的核心内容——内存管理,实现了从磁盘到内存额装载过程,实现了页表的创建,实现了内存的释放。缺陷是没有考虑到换入换出等动态的情况,也就是说在此做了一个假设:每个进程相互独立且对于每个单独的进程来说,内存空间是足够大的。
程序的输入非即时的,而是通过事先设定好的5个进程加上运行后随机生成的若干进程,也是为了模拟实际情况考虑。
因为全手工输入需要输入进程的到达时间,也就是需要根据到达时间来为缓冲池中进程排序的问题,但实际情况下到达时间是多余的,先创建的先加入队列即可,所以采用了随机生成的方式。
为了此次实验,复习了调度和内存管理两章的大部分内容,对操作系统对进程调度和内存分配管理有了更深入的认识,但只是从概念上,没有看到真正操作系统的代码或者算法实例,所以可能很多地方的代码与实际情况出入很大。
/*进程状态*/
int state ;
/*程序计数器*/
int pc[2] ;
/* cpu寄存器*/
//
/* cpu调度信息*/
//
/*记账信息,这里是运行时间*/
int run_time ;
/*内存管理信息,这里就是页表*/
list<PageTableNode> PageTable ;
/**
找到程序所在页对应的帧号
}
};
/*页表节点*/
class PageTableNode
{
public:
/*页号*/
int page_number ;
/*帧号*/
int frame_number ;
PageTableNode(const int& page, const int& frame)
{
page_number = page ;
}
/**
构造函数
@param1编号
@param2内容
**/
Program(const int& n, const string& s)
{
this->number = n ;
for (int i = 0 ; i < s.size() ; i++)
v.push_back(s[i]) ;
fragmentation() ;
运行结果
在编号为1的进程中的第一个内存单位设置了一条I/O指令,可以看出其发生中断后等待I/O完成才重新回到ReadyQueue中并执行完毕。
以上结果是在内存足够大的情况,下面再看一组内存不能同时满足需求的情况
此次内存设为11帧,编号为1的进程需要10帧,编号为2的进程需要1帧,我们看到,2号进程顺利载入并执行了,但其他进程都要等到1号进程执行完释放内存后才能载入内存,符合预期情况。
{
list<PageTableNode>::iterator p = PageTable.begin() ;
while (p != PageTable.end())
{
if (page == p->page_number)
return p->frame_number ;
else
p++ ;
}
if ( p == PageTable.end())
/*********************************************************************************/
/*这个文件用来保存生成的页表的*/
ofstream outfile ;
class PCB
{
public:
/*进程编号*/
int number ;
Job_scheduler的作用如下图所示;
Job_scheduler从大容量存储设备上的缓冲池中载入新生成的进程到内存,同时生成新的PCB到就绪队列中。
这里涉及到了两个数据结构class Program,class PCB。
Program:
PCB:
PCB中的state包含五个状态NEW、READY、RUN、WAITING、TERMINATED,加入到ReadyQueue中等待运行的PCB均为READY状态的,运行中会被置为RUN,
int page_numbers ;
/*计算需要的页的数目,向下取整*/
void fragmentation()
{
page_numbers = v.size() / FRAME ;
if (page_numbers * FRAME < v.size())
page_numbers ++ ;
//cout << page_numbers << endl;
#define OFF 0
#define ON 1
/*页大小*/
#define PAGE 1
/*帧大小*/
#define FRAME 1
/*内存里面分成的帧的数目*/
#define MEMORY 11
int Memory[MEMORY * FRAME] ;
/*初始化内存*/
void InitMEM()
/***************随机数,后面随机生成进程用的*************/
void rand_seed()
{
int seed = static_cast<int>(time(0)) ;
srand(seed) ;
}
int rand_int(int a, int b)
{
return a + rand() % (b - a + 1);
}
/****************随机数,后面随机生成进程用的*************/
int AddOfIO = 0 ;
int pcr[2] = {0, 0} ;
/*进程状态*/
#define NEW 0
#define READY 1
#define RUN 2
#define WAITING 3
相关主题