操作系统实验连接
实验一 进程调度算法
实验二 预防死锁-银行家算法
实验三 分区分配算法+请求式分页存储管理算法
实验四 文件系统
第三次操作系统实验也太麻烦了,完全就是各种算法的累加。。。
但是,看懂就是收获!
分区分配算法+请求式分页存储管理算法
一、分区分配算法
和以前一样,操作系统代码还是先看懂再改,原作者链接如下:
https://blog.csdn.net/Houchaoqun_XMU/article/details/55541299
数据结构
为了实现分区分配,系统中必须配置相应的数据结构,用来描述空闲分区和已分配分区的情况,为分配提供依据。常用的有空闲分区表和空闲分区链两种形式。我采用的是空闲分区表,将数据作为空闲分区表记录每个空闲分区的情况。每个空闲分区占数组中一个元素,数据元素为值为分区大小、数组下标为分区始址。
1、首次适应算法
- 这里以空闲分区链为例说明各算法,首次适应算法要求空闲分区链以地址递增的次序排列。在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止;
- 然后再按照作业的大小,从该分区中划出一块内存空间分配给请求者,余下的空闲分区仍留在空闲链中;
- 若从链首直至链尾都不能找到一个能满足要求的分区,则此次内存分配失败,返回。
- 首次适应算法倾向于优先利用内存中低址部分的空闲分区,从而保留了高址部分的大空闲区。这给为以后到达的大作业分配大的内存空间创造了条件。其缺点是低址部分不断被划分,会留下许多难以利用的、很小的空闲分区,而每次查找又都是从低址部分开始,这无疑会增加查找可用空闲分区时的开销。
2、最佳适应算法
- 所谓“最佳”是指每次为作业分配内存时,总是把能满足要求、又是最小的空闲分区分配给作业,避免“大材小用”。为了加速寻找,该算法要求将所有的空闲分区按其容量以从小到大的顺序形成一空闲分区链。这样,第一次找到的能满足要求的空闲区,必然是最佳的,并且在每一次分配完一个进程后,都要重新进行排序。
- 孤立地看,最佳适应算法似乎是最佳的,然而在宏观上却不一定。因为每次分配后所切割下来的剩余部分总是最小的,这样,在存储器中会留下许多难以利用的小空闲区。
数据
9
16 16 8 32 64 32 8 16 64
6
A B C D E F
7 18 9 20 35 8
完整代码
// 操作系统_实验三(动态分区分配算法)
//首次适应算法,最佳适应算法
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
#define MAXNUMBER 100
static int PartitionNum; //内存中空闲分区的个数
static int ProcessNum; //需要分配的进程个数
static int FreePartition[MAXNUMBER]; //空闲分区对应的内存
static int ProcessNeed[MAXNUMBER]; //需要分配的进程大小
static int LeftFreePartition[MAXNUMBER];
static int LeftProcessNeed[MAXNUMBER];
static char ProcessName[MAXNUMBER]; //需要分配的进程的编号
static char NameProcessToPartition[MAXNUMBER][MAXNUMBER]; //存储各个进程所在分区
typedef struct
{
int partitionSize;
int id;
}sortNeed;//分区表结构
void readDataFunction()
{
ifstream readData;
readData.open("data.txt");
readData>>PartitionNum;
for (int i=0;i<PartitionNum;i++)
{
readData>>FreePartition[i];
}
readData>>ProcessNum;
for (int i=0;i<ProcessNum;i++)
{
readData>>ProcessName[i];
}
for (int i=0;i<ProcessNum;i++)
{
readData>>ProcessNeed[i];
}
}
void display()
{
int i;
cout<<"需要分配内存的进程名:"<<endl;
for (i = 0;i<ProcessNum;i++)
{
cout<<"\t"<<ProcessName[i];
}
cout<<endl;
cout<<"需要分配内存的进程分区大小:"<<endl;
for (i = 0;i<ProcessNum;i++)
{
cout<<"\t"<<ProcessNeed[i];
}
cout<<endl;
cout<<"分配结果:"<<endl;
cout<<"分区序号:";
for (i = 0;i<PartitionNum;i++)
{
cout<<"\t"<<"分区"<<i+1<<" ";
}
cout<<endl<<"分区大小:";
for (i = 0;i<PartitionNum;i++)
{
cout<<"\t"<<FreePartition[i]<<" ";
}
cout<<endl<<"剩余大小:";
for (i = 0;i<PartitionNum;i++)
{
cout<<"\t"<<LeftFreePartition[i]<<" ";
}
cout<<endl<<"分配情况:"<<endl; //遍历分区,输出所分配的进程编号
for (i = 0;i<PartitionNum;i++)
{
for (int j = 0;j<ProcessNum;j++)
{
if (NameProcessToPartition[j][i]!=NULL)
{
cout<<NameProcessToPartition[j][i]<<": (分区"<<i+1<<")"<<endl;
}
}
}
cout<<endl<<"********结束**********"<<endl<<endl;
}
void initial()
{
readDataFunction(); //读取原始数据
for (int i=0;i<ProcessNum;i++) //遍历每一个进程
{
for (int j =0;j<PartitionNum;j++) //遍历每一个分区
{
NameProcessToPartition[i][j] =NULL;
LeftFreePartition[j] = FreePartition[j];
}
}
for (int i = 0;i<ProcessNum;i++)
{
LeftProcessNeed[i] = ProcessNeed[i];
}
}
void FirstFit()
{
cout<<endl<<"***********首次适应算法***********"<<endl;
initial();
int i,j;
for (i = 0;i<ProcessNum;i++) //逐个遍历每个进程
{
for (j = 0;j<PartitionNum;j++) //每次都从分区的首地址开始查找
{
if (LeftProcessNeed[i] <= LeftFreePartition[j] && LeftFreePartition!=0) //当系统内存分区足够大的时候,即分配给进程资源
{
LeftFreePartition[j] -= LeftProcessNeed[i]; //扣除分配给进程的资源
LeftProcessNeed[i] = 0; //当且仅当系统内存分区足够时才执行,即当前进程大小置0
NameProcessToPartition[i][j] = ProcessName[i]; //存储各个进程所在的分区位置
break; //!!!很重要,一个进程分区完后,应该立即break,进行下一个进程的判断
}
}
}
display();
}
void BestFit()
{
//思想:利用冒泡排序对分区大小进行排序,但不改变原分区的位置
//创建一个结构体,包括分区大小和所对应的id,每排序一次,分区大小、id随着改变
//关键:每次分配完一个进程的内存大小后,都要重新排序
cout<<endl<<"***********最佳适应算法***********"<<endl;
initial();
int i,j,temp,tempID;
sortNeed best[MAXNUMBER];
for (i = 0;i<PartitionNum;i++)
{
//初始化结构体
best[i].partitionSize = FreePartition[i];
best[i].id = i;
}
for (i = 0;i<ProcessNum;i++)
{
for (int s = PartitionNum - 1;s > 0;s--) //冒泡排序(每次分配完一个进程后,都需要重新排序)
{
for (int t = 0;t < s;t++)
{
if (best[s].partitionSize < best[t].partitionSize)
{
temp = best[s].partitionSize;
best[s].partitionSize = best[t].partitionSize;
best[t].partitionSize = temp;
tempID = best[s].id;
best[s].id = best[t].id;
best[t].id = tempID;
}
}
}
for (j = 0;j<PartitionNum;j++)
{
if (LeftProcessNeed[i] <= best[j].partitionSize)
{
best[j].partitionSize -= LeftProcessNeed[i];
LeftProcessNeed[i] = 0;
//保存各分区所分配的进程编号
NameProcessToPartition[i][best[j].id] = ProcessName[i];
break;
}
}
LeftFreePartition[best[j].id] = best[j].partitionSize;
}
display();
}
void selectAlgorithm(int chooseAlgorithm)
{
switch(chooseAlgorithm)
{
case 0:break;
case 1:FirstFit();break;
case 2:BestFit();break;
default:cout<<"请输入正确的序号:"<<endl;
}
}
int main()
{
int chooseAlgorithm = 3;
while(chooseAlgorithm)
{
cout<<"请选择实现的算法:"<<endl;
cout<<"***** 1 - 首次适应算法 *****"<<endl;
cout<<"***** 2 - 最佳适应算法 *****"<<endl;
cout<<"***** 0 - 结束 *****"<<endl;
cout<<endl;
cout<<"chooseAlgorithm = ";
cin>>chooseAlgorithm;
selectAlgorithm(chooseAlgorithm);
}
return 0;
}
二、请求式分页存储管理算法
请求式分页存储管理算法的代码,后面都没有问题,但是针对我的数据,页面序列前三个没有重复的则是对的,有重复的话会有点问题
1、先进先出算法(FIFO)
该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。该算法实现简单,只需把一个进程已调入内存的页面,按先后次序链接成一个队列,并设置一个指针,称为替换指针,使它总是指向最老的页面。例如分配一个作业的存储块数为m,则只需建立一张m个元素的队列表Q(0)、Q(1)、…、Q(m-1)和一个替换指针。新调进的页面装入主存后,修改相应的队列元素,然后将替换指针往前移动,使其指向当前最老的一页。
2、最近最少使用页面淘汰算法(LRU)
这是一种经常使用的方法,有多种不同的实施方案。这里采用不断调整页表链的方法,即总是淘汰页表链链首的页面,而把新访问的页面插入链尾。如果当前调用页面已在页表内,则把它再次调整到链尾。这样就能保证最近使用的页面总处于靠近链尾部分,而不常使用的页面被移到链首,逐个被淘汰。
数据
3
20
7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
完整代码
// 操作系统_实验五(虚拟内存页面置换算法)
//先进先出FIFO
//最近最少使用LRU
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
const int MaxNumber=100;
int PageOrder[MaxNumber]; //页面序列
int PageNum,LackNum,MinBlockNum; //页面个数,缺页次数,最小物理块数
int PageDisCount[MaxNumber]; //当前内存距离下一次出现的距离
int LRUtime[MaxNumber]; //存储队列中各个页面最近使用情况
double LackPageRate; //缺页率
int LackPageNum; //缺页数
int VirtualQueue[MaxNumber]; //虚拟队列
void input()
{
ifstream readData;
readData.open("data.txt");
readData>>MinBlockNum;
readData>>PageNum;
for (int i=0;i<PageNum;i++)
{
readData>>PageOrder[i];
}
cout<<"读取数据结果如下:"<<endl;
cout<<"最小物理块数 = "<<MinBlockNum<<endl;
cout<<"页面个数 = "<<PageNum<<endl;
cout<<"页面序列如下:"<<endl;
for (int i = 0;i<PageNum;i++)
{
cout<<PageOrder[i]<<" ";
}
cout<<endl;
}
void display()
{
for (int i = 0;i<MinBlockNum && VirtualQueue[i]>=0;i++)
{
cout<<VirtualQueue[i]<<" ";
}
cout<<endl;
}
void initial()
{
LackPageNum = MinBlockNum;
LackPageRate = 0.0;
for(int i = 0;i<PageNum;i++)
{
PageDisCount[i] = 0; //初始化距离都为0
VirtualQueue[i] = -1; //初始化队列的值都为负数
}
for (int i = 0;i<MinBlockNum;i++)
{
bool isInQueue2 = false;
int dis = 0;
LRUtime[i] = 0;//在最小物理块内赋0,因为一次只能存这么多页面
for (int j = 0;j<MinBlockNum;j++)
{
if (VirtualQueue[j] == PageOrder[i])//在初始化中PageOrder只取了前三个值
{
isInQueue2 = true;
}
}
if (!isInQueue2) //当有新的页面进入到队列时,便计算其对应的距离
{
VirtualQueue[i] = PageOrder[i];//先将存储队列占满
for (int k = 0;k<i;k++)
{
LRUtime[k]++; //之前的页面对应的时间+1
}
display();
}
else
{
LRUtime[i] = 0; //重新更新为0,表示最近刚刚使用
}
}
}
void FIFO()
{
cout<<"********* 你选择了FIFO算法:********* "<<endl;
cout<<"页面置换情况如下:"<<endl;
initial();
bool isInQueue;
int point = 0; //指向最老的页面
for (int i = MinBlockNum;i<PageNum;i++)
{
isInQueue = false;
for (int k = 0;k<MinBlockNum;k++)
{
if (PageOrder[i] == VirtualQueue[k]) //如果当前页面在队列中
{
isInQueue = true;
}
}
if (!isInQueue) //如果当前页面不在队列中,则进行相应的处理
{
LackPageNum++; //缺页数加1
VirtualQueue[point] = PageOrder[i];
display();
point++;//这个替换指针真的是太优秀了
if (point == MinBlockNum)
{
point = 0; //当point指向队尾后一位的时候,将point重新指向队首
}
}
}
LackPageRate = (LackPageNum * 1.0)/PageNum;
cout<<"缺页数LackPageNum = "<<LackPageNum<<endl;
cout<<"缺页率LackPageRate = "<<LackPageRate<<endl<<endl;
}
void LRU()
{
cout<<"********* 你选择了LRU算法:********* "<<endl;
cout<<"页面置换情况如下:"<<endl;
initial();
bool isInQueue;
int point,k; //指向最长时间未被访问的下标
for(int i = MinBlockNum;i<PageNum;i++)
{
isInQueue = false;
for (k = 0;k<MinBlockNum;k++)
{
if (PageOrder[i] == VirtualQueue[k]) //如果当前页面在队列中
{
isInQueue = true;
}
}
if (!isInQueue)
{
LackPageNum++;
point = 0;
for (int j = 1;j<MinBlockNum;j++)
{
if (LRUtime[point]<LRUtime[j])
{
point = j;//将point指向时间最大的那一个
}
}
for (int s = 0;s<MinBlockNum;s++)//其余页面对应的时间要+1
{
if (VirtualQueue[s] != VirtualQueue[point])
{
LRUtime[s]++;
}
}
VirtualQueue[point] = PageOrder[i];
LRUtime[point] = 0;
display();
}
else //负责更新当前对应页面的时间
{
for (int s = 0;s<MinBlockNum;s++)//其余页面对应的时间要+1
{
if (VirtualQueue[s] != PageOrder[i])
{
LRUtime[s]++;
}
else
LRUtime[s] = 0;
}
}
}//for
LackPageRate = (LackPageNum*1.0)/PageNum;
cout<<"缺页数LackPageNum = "<<LackPageNum<<endl;
cout<<"缺页率LackPageRate = "<<LackPageRate<<endl<<endl;
}
int main()
{
input();
int chooseAlgorithm = 1;
while(chooseAlgorithm)
{
cout<<"********* 请选择 **********"<<endl;
cout<<"********* 1 - 代表FIFO算法 **********"<<endl;
cout<<"********* 2 - 代表LRU算法 **********"<<endl;
cout<<"********* 0 - 退出程序 ! **********"<<endl;
cin>>chooseAlgorithm;
switch(chooseAlgorithm)
{
case 0:
break;
case 1:
FIFO();
break;
case 2:
LRU();
break;
default:
cout<<"请输入正确的序号进行选择:"<<endl;break;
}
}
cout<<"***************************结束***************************"<<endl;
return 0;
}