实验二 Allocation & Reclaim实验报告
一、实验目的与内容
在可变分区管理方式下,采用最先适应算法实现主存空间的分配和回收
要求与提示:
1、自行假设主存空间大小,预设操作系统所占大小并构造未分分区表;
表目内容:起址、长度、状态(未分/空表目)
2、结合实验一,PCB增加为:
{PID,要求运行时间,优先权,状态,所需主存大小,主存起始位置,PCB指针}
3、采用最先适应算法分配主存空间;
4、进程完成后,回收主存,并与相邻空闲分区合并。
二、需求分析
- 提供适宜大小的主存空间
- 设置操作系统所占用的固定内存大小以及可供分配的内存空间
- 为进行作业调度之后进入就绪队列的进程分配对应大小的内存空间
- 判断是否有足够的内存空间来执行进程
- 设置挂起队列,将挂起的队列的占用的内存从主存空间移除
- 将解挂的进程进行判定,如果可以移入就绪队列,那就进行判定,如果这段内存空间有足够的内存供分配,那就将为就绪队列分配所需要的内存空间
- 进程运行结束,回收该进程所占用的内存空间
- 如果有两块连续的未分配的内存空间,那就将这两段内存空间合并
- 进行ui设计
三、概要设计
- 划分各大模块,如显示界面模块,算法模块,类模块,进程移入移出模块等
- 设计ui使界面更加美观,增强实用性,分配未分配空间使用不同颜色显示,而且增加仪表盘,使分配内存占用大小更加直观。
- 采用表格,将各个队列的进程情况显示出来,并且显示内存空间
- 点击作业调度会将进程通过优先级算法从后备队列分配到就绪队列,内存空间则采用最先适应算法进行分配。
- 程序运行结束主动释放对应的内存空间。
- 当两个空闲内存区域相邻的时候,则进行合并,合并成为一个内存空闲区。
- 挂起解挂对内存区域进行相应的修改,原理同上。
四、详细设计
- 图形化界面
首先是开始界面,需要输入道数和cpu数,然后将参数传入到主界面中,在主界面新建进程,新建进程之后点击作业调度以及进程调度,提供挂起解挂输入框,进行挂起解挂操作
2、在PCB类之中,增加一个 int place用于表示进程所占用的内存大小,并且在showreservequeque,showreadyqueque等函数中加入显示占用内存大小的QWidgetitem。
class PCB
{
int PID;
QString name;
int runtime;
int priority;
int place;
public:
// bool operator<(const PCB& a)const //重载 < 操作符,用于进程间优先级比较
// {
// return (priority < a.priority) ;
// }
// static bool compareByValue(const PCB &a, const PCB &b) {
// return a.priority < b.priority;
// }
PCB() = default;
PCB(QString name,int PID,int runtime,int priority,int place)
{
this->name=name;
this->PID=PID;
this->runtime=runtime;
this->priority=priority;
this->place=place;
}
//拷贝构造函数
PCB(const PCB &other) {
this->PID = other.PID;
this->name = other.name;
this->runtime = other.runtime;
this->priority = other.priority;
this->place=other.place;
}
int getPID()
{
return PID;
}
int getPID()const
{
return PID;
}
QString getName()
{
return name;
}
int getRuntime()
{
return runtime;
}
int getRuntime()const
{
return runtime;
}
int getPriority()
{
return priority;
}
int getPriority()const
{
return priority;
}
int getPlace(){
return place;
}
int getPlace()const{
return place;
}
void changeRuntime( int m)
{
runtime=m;
}
};
3、设置函数算法判断该进程能否进入就绪队列ifintoreadyqueque(),将所需要的内存空间和所剩最大快内存空间进行比较,如果可以进入则将进程加入主存空间,进入就绪队列。
4、建立Passrate类,用于显示仪表盘中内存占比
#ifndef PASSRATE_H
#define PASSRATE_H
#include <QWidget>
#include <QtGlobal>
#include <QPainter>
#include <QPaintEvent>
#include <QPen>
#include<cmath>
#include<QLabel>
namespace Ui {
class Passrate;
}
class Passrate : public QWidget
{
Q_OBJECT
public:
explicit Passrate(QWidget* parent = 0);
~Passrate();
void paintEvent(QPaintEvent* event);//重绘事件
void updateValue(float value, float range);//更新展示的值,触发事件重绘
void drawLines(QPainter* painter);//绘制最外围的线
void drawBGE(QPainter* painter);//绘制中间最外层背景
void drawTextE(QPainter* painter);//绘制中心文字背景
void drawText(QPainter* painter);//绘制中心文字
void drawCircleOut(QPainter* painter);
void drawPointer(QPainter* painter);//绘制指针
int getValue() const;
private:
Ui::Passrate* ui;
int lineCount; //总的最外层线的条数
int value; //值
int textSize; //文本大小
int bgERadius; //背景直径
int radius0;
int radius1; //最外圈的刻度线对应直径
int radius2; //短线内圈刻度线对应直径
int radius3; //长线内圈刻度线对应直径
int textOutRadius; //文本背景外层直径
int textInnRadius; //文本背景内存直径
float range;
};
#endif // PASSRATE_H
5、设立partition结构体,用于显示内存占用情况的表格
typedef struct Partition {
//起始地址
int addressMemory;
//地址长度
int size;
//分区状态
QString state;
QString PID = " ";
}Partition;
6、设定最先适应分配算法,用来寻找第一个适合分配的内存空间
int MainWindow::getIndexOfFirstFit(int size)
{
//将未分区表按照地址由小到大排列
for (int i = 1; i < partitionQueue.size(); i++)
{
if (partitionQueue[i - 1]->addressMemory > partitionQueue[i]->addressMemory && partitionQueue[i - 1]->PID != "OS操作系统")
{
Partition* partition = new Partition;
partition = partitionQueue[i - 1];
partitionQueue[i - 1] = partitionQueue[i];
partitionQueue[i] = partition;
}
}
refreshTable(partitionQueue, partitionModel);
printPartition();
for (int i = 0; i < partitionQueue.size(); i++)
{
if (partitionQueue[i]->size >= size && partitionQueue[i]->state == "未分")
{
return i;
}
}
}
7、点击进程调度之后,情况和实验一类似,内存空间没有变动,具体原理参考实验一。
8、程序运行结束之后,将进程所占用的主存空间进行回收,所占用的内存空间从已分配转为未分配,具体操作的代码如下
PCB p=runqueque.at(0);
int index=getIndexOfPIDFit(p.getPID());
int size=p.getPlace();
Partition*partition=new Partition;
partition->PID="";
partition->state="未分";
partition->size=size;
partition->addressMemory=partitionQueue[index]->addressMemory;
partitionQueue[index]->addressMemory = partitionQueue[index]->addressMemory + size;
if(partitionQueue[index]->size - size==0)
{
partitionQueue.removeAt(index);
}
else
{
partitionQueue[index]->size = partitionQueue[index]->size - size;
}
partitionQueue.insert(index, partition);
refreshTable(partitionQueue, partitionModel);
combineFreeplace(index);
donequeque=moveprcfromRuntoDone(&runqueque);
runqueque=moveprcfromRdytoRun(&readyqueque);
passrate->updateValue(getSumOfAllBusySize(), getRange());
passrate->show();
9、点击挂起队列之后,程序会将进程从就绪队列移动到挂起队列,其占用的内存也会被回收,这样就绪队列数就会少于计算机道数,程序会自动从后被队列之中取出一个可以进入内存的进程分配到就绪队列,为其分配内存空间。
void MainWindow::on_pushButton_6_clicked()
{
if(ifIntoReadyqueque(hangPID))
{
timer2->stop();
PCB p=readyqueque.at(process_num-1);
int index=getIndexOfPIDFit(p.getPID());
int size=p.getPlace();
Partition*partition=new Partition;
partition->PID="";
partition->state="未分";
partition->size=size;
partition->addressMemory=partitionQueue[index]->addressMemory;
partitionQueue[index]->addressMemory = partitionQueue[index]->addressMemory + size;
if(partitionQueue[index]->size - size==0)
{
partitionQueue.removeAt(index);
}
else
{
partitionQueue[index]->size = partitionQueue[index]->size - size;
}
partitionQueue.insert(index, partition);
refreshTable(partitionQueue, partitionModel);
combineFreeplace(index);
reservequeque=moveprcfromRdytoRsv(&readyqueque);
PCB pcb=hangupqueque.at(getHangquequei());
int index1;
int size1=pcb.getPlace();
index1=getIndexOfFirstFit(size1);
Partition* p1=new Partition;
p1->PID=QString::number(pcb.getPID());
p1->state="已分";
p1->size=size1;
p1->addressMemory=index1;
p1->addressMemory = partitionQueue[index1]->addressMemory;
partitionQueue[index1]->addressMemory = partitionQueue[index1]->addressMemory + size1;
partitionQueue[index1]->size = partitionQueue[index1]->size - size1;
partitionQueue.insert(index1, p1);
refreshTable(partitionQueue, partitionModel);
timer2->start(1000);
readyqueque=moveprcfromHangtoRdy(&hangupqueque);
readyqueque=sort1(readyqueque);
passrate->updateValue(getSumOfAllBusySize(), getRange());
passrate->show();
}
}
10、设立getbusysize函数和getrange函数,用于返回内存空间占用情况,函数代码如下:
int MainWindow::getSumOfAllBusySize()
{
int m = 0;
for (int i = 0; i < partitionQueue.size(); i++)
{
if (partitionQueue[i]->state == "已分")
m += partitionQueue[i]->size;
}
m = m + 20;
return m;
}
int MainWindow::getRange()
{
float m = 45 + getSumOfAllBusySize() * 2.7;
return m;
}
五、程序代码:
代码地址:https://gitee.com/little-penguin-writeCode/os_ex1_-cpu-scheduling.git