实验一《CPU Scheduling》
实验学时: 4 实验地点: 二综203 实验日期: 2022年10月28日
一、实验目的
多道系统中,当就绪进程数大于处理机数时,须按照某种策略决定哪些进程优先占用处理机。本实验模拟实现处理机调度,加深了解处理机调度的工作过程。
二、实验内容
选择一个调度算法,实现处理机调度。
1、设计一个按优先权调度算法实现处理机调度的程序;
2、设计按时间片轮转实现处理机调度的程序。
三、实验方法
本实验具体功能由Qt实现,并完成相关图形化界面设计,并在调度过程中加入动画,可以比较直观的看到cpu调度过程。
四、实验过程
1、概要设计
(1)、在实验中始终可以查看各个进程的状态。
(2)、如果内存中进程数少于规定道数,可自动从后备队列通过作业调度选择一作业 进入。
(3)、cpu调度可以实现抢占式优先级调度和时间片轮转两种形式。
(4)、进程调度过程可以使用自动进行和手动一步一步演示两种方式。
(5)、被挂起进程入挂起队列,设置解挂功能用于将指定挂起进程解挂并入就绪队列。
(6)、可动态增加进程。
(7)、可清空后备队列。
(8)、在就绪队列进程进入cpu执行时增加动效。
2、详细设计
(1)、建立数据库,以及表示就绪队列、后备队列、挂起队列、终止队列的数据表。
//指定数据库驱动名,增加数据库实例
QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE");
//设置数据库用户名
db.setDatabaseName("user.db");
if(!db.open())
{
qDebug()<<"连接失败,失败原因:"<<db.lastError().text();
}
else
{
qDebug()<<"连接成功";
}
//创建一个存储后备队列的表
QString cmd="create table if not exists waiting( Pid verchar(64) ,time int ,priority int, state verchar(64) )";
if(query.exec(cmd))
{
qDebug()<<"waitingTable exce successful";
}
//创建一个存储就绪队列的表
QString cmd="create table if not exists ready( Pid verchar(64) ,time int ,priority int, state verchar(64) )";
if(query.exec(cmd))
{
qDebug()<<"readyTable exce successful";
}
//创建一个存储挂起队列的表
QString cmd="create table if not exists putup( Pid verchar(64) ,time int ,priority int, state verchar(64) )";
if(query.exec(cmd))
{
qDebug()<<"putupTable exce successful";
}
//创建一个存储终止队列的表
QString cmd="create table if not exists finish( Pid verchar(64) ,time int ,priority int, state verchar(64) )";
if(query.exec(cmd))
{
qDebug()<<"finishTable exce successful";
}
(2)、在UI界面当中用四个QTableView控件分别表示后备队列、就绪队列、挂起队 列、终止队列。
(3)、当进入界面时,数据库中后备队列数据表中的数据会显示在ui界面中表示后备 队列的QTableview的控件当中。
(4)、高级调度采用先到先服务的调度算法,摄制道数为5,当就绪队列中的进程数 少于道数且后备队列进程数不为0时,后备队列里的进程会进入就绪队列。
//设置道数为5,即就绪队列中最多储存5个数据
#define N 5
void Widget:: InsertIntoReadyqueue()
{
while((readyQueue.size<N)&&(waitingQueue.size!=0))
{
PCB *p=new PCB();
p->PID=waitingQueue.front->next->PID;
p->priority=waitingQueue.front->next->priority;
p->state=waitingQueue.front->next->state;
p->time=waitingQueue.front->next->time;
QString pid=p->PID;
int time=p->time;
int priority=p->priority;
EnQueue(readyQueue,p->PID,p->time,p->priority,"ready");
DeQueue(waitingQueue);
EnRecord(model2,pid,time,priority,"ready");
DeRecord(model);
}
}
(5)、在UI中增加一个表示调度方式的QComboBox的复选框控件,可以选择优先 级调度、时间片轮转两种cpu调度方式,可以通过改变复选框的内容来实现中途 两种调度方式的自由转换。
(6)、在UI中增加一个表示高级调度是自动进行还是手动进行的QComboBox的复 选框控件,当选择自动进行的时候每两秒会执行一次调度过程,中途可以由手动 切换为手动,也可以由自动切换为手动。
void Widget::setValue()
{
if(ui->autoComboBox->currentText()=="自动调度")
{
time->start(2000);
}
if(ui->autoComboBox->currentText()=="手动调度")
{
time->stop();
}
}
//每隔设定时间执行一次下一步操作
connect(time,SIGNAL(timeout()),this,SLOT(on_nextPushButton_cl icked()));
//当自动手动选择复选框内容改变的时候,改变自动手动方式
connect(ui->autoComboBox,SIGNAL(currentTextChanged(QString)), this,SLOT(setValue()));
(7)、在UI中增加一个表示挂起和解挂的按钮,可以将就绪队列中选定的进程挂起到挂起队列,也可以将挂起队列的进程解挂到就绪队列当中。
(8)、在UI中增加一个表示添加进程的按钮,点击后进入添加进程的子界面,添加 时会对根据该添加的进程PID在数据库中挂起队列、后备队列、就绪队列的数据 表中,以及当前运行的进程中查找,如果该进程名已存在,会跳出提示框请求重 新添加
(9)、在UI中增加一个表示清空后备队列的按钮,点击后将会清空后备队列和表示
数据库中表示后备队列的数据表。
(10)、 在就绪队列下面设置一个按钮来记录该队列排序后的队首元素,将按钮设置 为不可见,当需要就绪队列进cpu时可以让该按钮变为可见,并设置动画效果使其 飞入cpu执行区。
//设置动画效果
void Widget::beginAnimation()
{
p->raise();
p->setVisible(true);
animation->setPropertyName("geometry");
animation->setDuration(1000);
animation->setStartValue(QRect(470,330,300,50));
animation->setEndValue(QRect(470,555,300,50));
animation->start();
}
3、界面效果
五、实验代码
1、main.cpp主程序
#include "widget.h"
#include <QApplication>
#include <QDebug>
#include<QSqlError>
#include<QSqlQuery>
#include<QSqlQueryModel>
#include<QSqlTableModel>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
/**数据库部分
*
**/
//指定数据库驱动名,增加数据库实例
QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE");
//设置数据库用户名
db.setDatabaseName("user.db");
if(!db.open())
{
qDebug()<<"连接失败,失败原因:"<<db.lastError().text();
}
else
{
qDebug()<<"连接成功";
}
//创建一个存储后备队列的表
QString cmd="create table if not exists waiting( Pid verchar(64) ,time int ,priority int, state verchar(64) )";
QSqlQuery query;
if(query.exec(cmd))
{
qDebug()<<"waitingTable exce successful";
}
//创建一个存储ready队列的表
cmd="create table if not exists ready( Pid verchar(64) ,time int ,priority int, state verchar(64) )";
if(query.exec(cmd))
{
qDebug()<< "readyTable exce successful";
}
//创建一个存储完成队列的表
cmd="create table if not exists finish( Pid verchar(64) ,time int ,priority int, state verchar(64) )";
if(query.exec(cmd))
{
qDebug()<<"finishTable exce successful";
}
//创建一个挂起队列的表
cmd="create table if not exists putup( Pid verchar(64) ,time int ,priority int, state verchar(64) )";
if(query.exec(cmd))
{
qDebug()<<"putupTable exce successful";
}
Widget w;
w.show();
return a.exec();
}
- widget.h
//该文件表示主界面
#ifndef WIDGET_H
#define WIDGET_H
#include <QtSql/QSqlDatabase>
#include <QWidget>
#include <NewPcb.h>
#include<ui_Newpcb.h>
#include<QPaintEvent>
#include<QSqlTableModel>
#include<QStandardItemModel>
#include<QPropertyAnimation>
class NewPcb;
//定义结构体
typedef struct PCB{
QString PID;
//进程名
int time;
//要求运行时间,单位时间
QString state;
//状态
int priority;
//优先级
struct PCB *next;
//PCB指针
}PCB,*QueuePtr;
typedef struct {
QueuePtr front;
QueuePtr rear;
int size;
}linkQueue;
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_addPushButton_clicked();
void on_beginPushButton_clicked();
void on_putupPushButton_clicked();
void on_nextPushButton_clicked();
void on_pushButton_2_clicked();
void on_releasePutupPushButton_clicked();
void on_BeginPushButton_clicked();
void setValue();
void on_overPushButton_clicked();
void on_clearPushButton_clicked();
private:
Ui::Widget *ui;
NewPcb *newPcb;
PCB *running;
QPushButton *p;
QPropertyAnimation *animation;
QSqlTableModel *model;//后备队列可视化模型
QSqlTableModel *model2;//ready队列可视化模型
QSqlTableModel *model3;//挂起队列可视化模型
QSqlTableModel *model4;//完成队列可视化模型
QTimer *time;
void beginAnimation();
void paintEvent(QPaintEvent *p1);
void InsertIntoReadyqueue();
void InsertIntoRunning();
//对队列进行操作
bool SeQueue(linkQueue &Q,QString pid);
void initWaitingQueue(QSqlTableModel* model);
void initReadyQueue(QSqlTableModel* model1,QSqlTableModel* model2);
void initPutupQueue(QSqlTableModel* model);
void initFinishQueue(QSqlTableModel*model);
//对tableview同时也是对数据库进行处理
void EnRecord(QSqlTableModel *model,QString pid,int time,int priority,QString state );
void DeRecord(QSqlTableModel *model);
void EnRecordFront(QSqlTableModel *model, QString pid, int time, int priority, QString state);
// void priorityScheduling();//优先级调度算法
//关于队列的基本操作,分别为初始化队列,增加节点,删除节点
bool InitQueue(linkQueue &Q);
bool EnQueue(linkQueue &Q,QString pid,int time,int priority,QString state);
bool DeQueue(linkQueue &Q);
bool EnQueueFront(linkQueue &Q,QString pid,int time,int priority,QString state);
void sortReadyQueue();
// bool SortQueue(linkQueue &Q);
};
#endif // WIDGET_H
- newPcb.h
//该文件表示新加进程界面
#ifndef NEWPCB_H
#define NEWPCB_H
#include <QWidget>
#include <widget.h>
#include<QPaintEvent>
class Widget;
namespace Ui {
class NewPcb;
}
class NewPcb : public QWidget
{
Q_OBJECT
public:
explicit NewPcb(QWidget *parent = 0);
~NewPcb();
void setWidget(Widget *widget);
Widget *widget;
Ui::NewPcb *ui;
private slots:
void on_okPushButton_clicked();
void on_returnPushButton_clicked();
private:
void paintEvent(QPaintEvent *p1);
};
#endif // NEWPCB_H
- widget.cpp
//该文件表示主界面界面
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QSqlError>
#include<QSqlQuery>
#include<QSqlQueryModel>
#include<QSqlTableModel>
#include<QStyleOption>
#include<QPainter>
#include<QBitmap>
#include<QSqlRecord>
#include<QStandardItemModel>
#include<QTimer>
#include<QMessageBox>
//设置道数为5,即就绪队列中最多储存5个数据
#define N 5
//规定点击一次下一次后时间片减少多少
#define TIMESLICE 2
//规定点击一次下一次后优先级减少多少
//priority越大,优先级越高,越先执行
#define PRIORITYCHANGE 1
//进程状态枚举
enum STATE
{ WAITING,
READY,
RUNNING,
BLOCK,
FINISH
};
//初始化三个队列
linkQueue readyQueue;
linkQueue waitingQueue;
linkQueue putupQueue;
linkQueue finishQueue;
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
time=new QTimer(this);
//初始化动画
p=new QPushButton(this);
p->setGeometry(480,330,300,50);
p->setVisible(false);
const QString style={"QPushButton{color: #2f3640;background-color: #f5f6fa;border-radius: 15px;border-color: #2f3640;border-style: solid;border-width: 2px; padding: 5px;front:楷体 ;font-weight:bold ;}"};
p->setStyleSheet(style);
p->raise();
animation=new QPropertyAnimation();
animation->setTargetObject(p);
animation->setEasingCurve(QEasingCurve::Linear);//设置动画效果
//初始化当前运行进程指针
running=new PCB();
ui->setupUi(this);
newPcb=new NewPcb();
this->newPcb->setWidget(this);
//创建后备队列对应的模型
model=new QSqlTableModel(this);
model->setTable("waiting");
model->select();
ui->waintingQueueView->setModel(model);
initWaitingQueue(model);
//创建ready队列对应的模型
model2=new QSqlTableModel(this);
model2->setTable("ready");
model2->select();
ui->readyQueueView->setModel(model2);
initReadyQueue(model,model2);
//创建挂起队列对应的模型
model3=new QSqlTableModel(this);
model3->setTable("putup");
model3->select();
ui->putupQueueView->setModel(model3);
initPutupQueue(model3);
//创建完成队列对应的模型
model4=new QSqlTableModel(this);
model4->setTable("finish");
model4->select();
ui->finishQueueView->setModel(model4);
initFinishQueue(model4);
ui->pidPushButton->setVisible(false);
ui->timePushButton->setVisible(false);
ui->priorityPushButton->setVisible(false);
//往后备队列添加进程的时候同时判断几个队列是否含有该进程名,如果有返回给出警告
connect(newPcb->ui->okPushButton,&QPushButton::clicked,[=](){
QString pid=newPcb->ui->pidLineEdit->text();
int priority=newPcb->ui->priorityComboBox->currentText().toInt();
int time=newPcb->ui->timeLineEdit->text().toInt();
if(SeQueue(waitingQueue,pid)||SeQueue(readyQueue,pid)||SeQueue(putupQueue,pid)||(running->PID==pid))
{
QMessageBox::warning(this,"警告","该进程名已存在,请重新输入","OK");
}
else {
//添加数据库记录并同时对数据库进行修改
EnRecord(model,pid,time,priority,"waiting");
//对后备队列进行修改
EnQueue(waitingQueue,pid,time,priority,"waiting");
//如果就绪队列有位置,进入就绪队列
InsertIntoReadyqueue();
}
newPcb->ui->pidLineEdit->clear();
newPcb->ui->timeLineEdit->clear();
});
//每隔设定时间执行一次下一步操作
connect(time,SIGNAL(timeout()),this,SLOT(on_nextPushButton_clicked()));
//当自动手动选择复选框内容改变的时候,改变自动手动方式
connect(ui->autoComboBox,SIGNAL(currentTextChanged(QString)),this,SLOT(setValue()));
}
Widget::~Widget()
{
delete ui;
}
//该界面样式
void Widget::paintEvent(QPaintEvent *p1)
{
//绘制样式
QStyleOption opt;
opt.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);//绘制样式
QBitmap bmp(this->size());
bmp.fill();
QPainter painter(&bmp);
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::black);
painter.setRenderHint(QPainter::Antialiasing);
//painter.drawRoundedRect(bmp.rect(), 12, 12);
setMask(bmp);
}
void Widget::on_addPushButton_clicked()
{
this->newPcb->show();
this->hide();
}
//初始化后备队列
void Widget:: initWaitingQueue(QSqlTableModel* model)
{
// query.exec(QString("insert into cpuSchedule values('%1','%2','%3','%4')").arg("p5").arg(54).arg(32).arg("wainting"));
//显示设置
model->setHeaderData(0, Qt::Horizontal, "进程名称");
model->setHeaderData(1, Qt::Horizontal, "所需时间");
model->setHeaderData(2, Qt::Horizontal, "优先级");
model->setHeaderData(3, Qt::Horizontal, "当前状态");
ui->waintingQueueView->setColumnWidth(0, 124);
ui->waintingQueueView->setColumnWidth(1, 124);
ui->waintingQueueView->setColumnWidth(2, 124);
ui->waintingQueueView->setColumnWidth(3, 0);
QSqlQuery query("user.db");
query.exec("select *from waiting");
//创建空队列
InitQueue(waitingQueue);
//用数据库中的信息初始化tableview控件信息,初始化后备队列
while(query.next()) {
EnQueue(waitingQueue,query.value(0).toString(),query.value(1).toInt(),query.value(2).toInt(),query.value(3).toString());
qDebug()<<query.value(0).toString()<<query.value(1).toInt();
}
}
//初始化就绪队列
void Widget:: initReadyQueue(QSqlTableModel* model1,QSqlTableModel* model2)
{
//显示设置
model2->setHeaderData(0, Qt::Horizontal, "进程名称");
model2->setHeaderData(1, Qt::Horizontal, "所需时间");
model2->setHeaderData(2, Qt::Horizontal, "优先级");
model2->setHeaderData(3, Qt::Horizontal, "当前状态");
ui->readyQueueView->setColumnWidth(0, 124);
ui->readyQueueView->setColumnWidth(1, 124);
ui->readyQueueView->setColumnWidth(2, 124);
ui->readyQueueView->setColumnWidth(3, 0);
QSqlQuery query("user.db");
query.exec("select *from ready");
//创建新队列
InitQueue(readyQueue);
InsertIntoReadyqueue();
}
//初始化挂起队列
void Widget:: initPutupQueue(QSqlTableModel* model){
//显示设置
model->setHeaderData(0, Qt::Horizontal, "进程名称");
model->setHeaderData(1, Qt::Horizontal, "所需时间");
model->setHeaderData(2, Qt::Horizontal, "优先级");
model->setHeaderData(3, Qt::Horizontal, "当前状态");
ui->putupQueueView->setColumnWidth(0, 124);
ui->putupQueueView->setColumnWidth(1, 124);
ui->putupQueueView->setColumnWidth(2, 124);
ui->putupQueueView->setColumnWidth(3, 0);
InitQueue(putupQueue);
}
//初始化终止队列
void Widget:: initFinishQueue(QSqlTableModel* model){
//显示设置
model->setHeaderData(0, Qt::Horizontal, "进程名称");
model->setHeaderData(1, Qt::Horizontal, "所需时间");
model->setHeaderData(2, Qt::Horizontal, "优先级");
model->setHeaderData(3, Qt::Horizontal, "当前状态");
ui->finishQueueView->setColumnWidth(0, 124);
ui->finishQueueView->setColumnWidth(1, 124);
ui->finishQueueView->setColumnWidth(2, 124);
ui->finishQueueView->setColumnWidth(3, 0);
InitQueue(finishQueue);
}
/**
* 对队列数据结构进行操作
*
* */
bool Widget:: InitQueue(linkQueue &Q)
//构建一个空队列
{ Q.front=(QueuePtr) malloc((sizeof(PCB)));
Q.rear=Q.front;
//头指针和尾指针均指向头节点
if(!Q.front)
{
qDebug()<<"分配空间出现错误";
return false;
}
Q.size=0;
Q.front->next=NULL;
return true;
}
//从队列尾部添加元素
bool Widget:: EnQueue(linkQueue &Q,QString pid,int time,int priority,QString state)
{
QueuePtr p =new PCB;
if(!p)
{
qDebug()<<"分配空间出现错误";
return false;
}
p->PID=pid;
p->time=time;//正确
p->priority=priority;//错误
p->state=state;
qDebug()<<"添加链表元素"<<p->PID<<p->time<<p->priority<<p->state;
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
Q.size++;
return 0;
}
//从队列头部添加元素
bool Widget::EnQueueFront(linkQueue &Q,QString pid,int time,int priority,QString state)
{
if(Q.size==0)
{
EnQueue(Q,pid,time,priority,state);
return true;
}
else{
QueuePtr p =new PCB;
if(!p)
{
qDebug()<<"分配空间出现错误";
return false;
}
p->PID=pid;
p->time=time;
p->priority=priority;
p->state=state;
qDebug()<<"向链表头部添加元素"<<p->PID<<p->time<<p->priority<<p->state;
p->next=Q.front->next;
Q.front->next=p;
Q.size++;
return true;
}
}
bool Widget::DeQueue(linkQueue &Q)
{
//若队列不空,则删除队头元素,返回true;否则返回false
if(Q.size==0)
{
QMessageBox::information(this,tr("注意"),tr("该队列为空"));
return false;
}
PCB *p=Q.front->next;
Q.front->next=p->next;
if(Q.rear==p)
//即如果同时指向头节点
Q.rear=Q.front;
Q.size--;
free(p);
return true;
}
bool Widget::SeQueue(linkQueue &Q,QString pid)
{
PCB *p=new PCB;
p=Q.front->next;
while (p!=NULL) {
if(p->PID==pid)
return true;
p=p->next;
}
return false;
}
/**
*对图表进行改变
*/
void Widget::EnRecord(QSqlTableModel *model,QString pid,int time,int priority,QString state ){
//添加数据库记录并同时对数据库进行修改
QSqlRecord record = model->record() ; //获取空记录
int row = model->rowCount() ; //获取行数,该数字便是需要插入的行,因为行数不从0开始,而插入的行又得从0开始
record.setValue(0,pid);
record.setValue(1,time);
record.setValue(2,priority);
record.setValue(3,state);
model->insertRecord(row,record);
}
void Widget::EnRecordFront(QSqlTableModel *model,QString pid,int time,int priority,QString state ){
QSqlRecord record = model->record() ; //获取空记录
record.setValue(0,pid);
record.setValue(1,time);
record.setValue(2,priority);
record.setValue(3,state);
model->insertRecord(0,record);
}
void Widget::DeRecord(QSqlTableModel *model){
if((model->rowCount())>=1)
{
model->removeRow(0);
model->select();
}
}
/**
*一些按钮的槽函数
*
*
**/
//当点击挂起按钮的时候
void Widget::on_putupPushButton_clicked()
{
qDebug()<<"在此处挂起";
//获取ready表格选中的行
int cursor=ui->readyQueueView->currentIndex().row();
//获取选中该行信息
QModelIndexList list=ui->readyQueueView->selectionModel()->selectedIndexes();
//在挂起图表中增加一行,同时在挂起队列添加一个节点
EnRecord(model3,list[0].data().toString(),list[1].data().toInt(),list[2].data().toInt(),"putup");
EnQueue (putupQueue,list[0].data().toString(),list[1].data().toInt(),list[2].data().toInt(),"putup");
//ready队列当中删除该行
model2->removeRow(cursor);
model2->select();
//对下面的数据进行排序
QSqlQuery query;
if(query.exec("select *from ready order by PID DESC "))
//初始化ready队列
qDebug()<<"在此处初始化队列";
InitQueue(readyQueue);
while(query.next()) {
qDebug()<<query.value(0).toString()<<query.value(1).toInt();
EnQueue (readyQueue,query.value(0).toString(),query.value(1).toInt(),query.value(2).toInt(),"putup");
}
qDebug()<<readyQueue.size<<waitingQueue.size;
InsertIntoReadyqueue();
}
//解除挂起的时候
void Widget::on_releasePutupPushButton_clicked()
{
qDebug()<<"执行开始挂起";
//获取选中的行
int cursor=ui->putupQueueView->currentIndex().row();
//获取选中内容
QModelIndexList list=ui->putupQueueView->selectionModel()->selectedIndexes();
//在waiting图表头部增加一条记录
EnRecordFront(model,list[0].data().toString(),list[1].data().toInt(),list[2].data().toInt(),"waiting");
EnQueueFront(waitingQueue,list[0].data().toString(),list[1].data().toInt(),list[2].data().toInt(),"waiting");
//从挂起队列当中删除该条记录
model3->removeRow(cursor);
model3->select();
InsertIntoReadyqueue();
}
void Widget::on_overPushButton_clicked()
{
this->close();
}
//清空后备队列
void Widget::on_clearPushButton_clicked()
{
//将后备队列的数据库清空
QString cmd="delete from waiting";
//执行sql语句
QSqlQuery query;
if(query.exec(cmd))
{
qDebug()<<"waiting数据库清空 清空 successful";
}
initWaitingQueue(model);
model->select();
}
/**
*
*
**/
//将ready队列和模型按照优先级进行排序
void Widget::sortReadyQueue()
{
//按照优先级队列进行排序
model2->setSort(2, Qt::DescendingOrder);
model2->select();
QSqlQuery query;
if(query.exec("select *from ready order by priority DESC "))
qDebug()<<"laaaaa";
//初始化ready队列
InitQueue(readyQueue);
while(query.next()) {
qDebug()<<query.value(0).toString()<<query.value(1).toInt();
EnQueue(readyQueue,query.value(0).toString(),query.value(1).toInt(),query.value(2).toInt(),"ready");
}
}
//从就绪队列中选取队首元素进入cpu执行,就绪队列减少一条数据
void Widget::InsertIntoRunning()
{
PCB *p1=new PCB;
p1->PID=readyQueue.front->next->PID;
p1->time=readyQueue.front->next->time;
p1->priority=readyQueue.front->next->priority;
p1->state=readyQueue.front->next->state;
running=p1;
QString pid2=running->PID;
int time2=running->time;
int priority2=running->priority;
QString time2_0=tr("%1").arg(time2);
QString priority2_0=tr("%1").arg(priority2);
ui->pidPushButton->setText(pid2);
ui->timePushButton->setText(time2_0);
ui->priorityPushButton->setText(priority2_0);
p->setText(pid2+" "+time2_0+" "+priority2_0);
beginAnimation();
DeQueue(readyQueue);
DeRecord(model2);
}
void Widget:: InsertIntoReadyqueue()
{
while((readyQueue.size<N)&&(waitingQueue.size!=0))
{
PCB *p=new PCB();
// p=waitingQueue.front->next;//获取waiting队列队首元素
p->PID=waitingQueue.front->next->PID;
p->priority=waitingQueue.front->next->priority;
p->state=waitingQueue.front->next->state;
p->time=waitingQueue.front->next->time;
QString pid=p->PID;
int time=p->time;
int priority=p->priority;
EnQueue(readyQueue,p->PID,p->time,p->priority,"ready");
DeQueue(waitingQueue);
EnRecord(model2,pid,time,priority,"ready");
DeRecord(model);
}
}
void Widget::on_nextPushButton_clicked()
{ //保证在空队列中增加元素时能够继续启动
InsertIntoReadyqueue();
if(ui->schedulingComboBox->currentText()=="优先级调度")
{
if(running->PID==""&&readyQueue.size>0)
{
sortReadyQueue();
//就绪队列进cpu
InsertIntoRunning();
//后备队列进入就绪队列
InsertIntoReadyqueue();
//就绪队列进行排序
sortReadyQueue();
//进行抢占
if(readyQueue.size>0&&running->priority<readyQueue.front->next->priority&&running!=NULL&&readyQueue.size>0)
{
PCB*p=new PCB;
p=running;
//将就绪队列队首元素调进CPU执行
InsertIntoRunning();
//将原cPu执行元素调到就绪队列队首
EnQueueFront(readyQueue,p->PID,p->time,p->priority,"ready");
//在ready队列视图加入该元素
EnRecordFront(model2,p->PID,p->time,p->priority,"ready");
}
return;
}
if (running->PID!="") {
sortReadyQueue();
//进行抢占,运行期间在就绪队列中增加高优先级进程,应立即进入running队列
if(running->PID!=""&&readyQueue.size>0&&running->priority<readyQueue.front->next->priority)
{
PCB*p=new PCB;
p=running;
//将就绪队列队首元素调进CPU执行
InsertIntoRunning();
//将原cPu执行元素调到就绪队列队首
EnQueueFront(readyQueue,p->PID,p->time,p->priority,"ready");
//在waiting队列视图加入该元素
EnRecordFront(model2,p->PID,p->time,p->priority,"ready");
sortReadyQueue();
}
//所需运行时间减少
running->time= running->time-TIMESLICE;
running->priority=running->priority-PRIORITYCHANGE;
int time1=running->time;
int priority1=running->priority;
QString time1_0=tr("%1").arg(time1);
QString priority1_0=tr("%1").arg(priority1);
ui->priorityPushButton->setText(priority1_0);
ui->timePushButton->setText(time1_0);
p->setText(running->PID+" "+time1_0+" "+priority1_0);
if(running->time<=0)
{
//在终止队列里添加元素
EnQueue(finishQueue,running->PID,0,running->priority,"finish");
//在终止队列视图中添加元素
EnRecord(model4,running->PID,0,running->priority,"finish");
running->PID="";
ui->priorityPushButton->setText("");
ui->timePushButton->setText("");
ui->pidPushButton->setText("");
p->setText("");
if(readyQueue.size>0)
{
sortReadyQueue();
//从就绪队列中选取第一条数据插入
InsertIntoRunning();
//从后备队列里选取一条数据插入就绪队列
InsertIntoReadyqueue();
//将就绪队列和就绪视图进行排序
sortReadyQueue();
}
}
//进行抢占,如果运行完优先级低于就绪队列队首,将其置于后备队列
if(running->PID!=""&&readyQueue.size>0&&running->priority<readyQueue.front->next->priority)
{
PCB*p=new PCB;
p=running;
//将就绪队列队首元素调进CPU执行
InsertIntoRunning();
//将原cPu执行元素调到就绪队列队首
EnQueueFront(readyQueue,p->PID,p->time,p->priority,"ready");
//在waiting队列视图加入该元素
EnRecordFront(model2,p->PID,p->time,p->priority,"ready");
sortReadyQueue();
}
return;
}
//即当后备队列和就绪队列均为空的时候
if(running->PID==""&&readyQueue.size==0)
{
return;
}
}
if(ui->schedulingComboBox->currentText()=="时间片调度")
{
if(running->PID==""&&readyQueue.size>0)
{
InsertIntoRunning();
InsertIntoReadyqueue();
return;
}
if(running->PID!="")
{
running->time=running->time-TIMESLICE;
int time1=running->time;
int priority1=running->priority;
QString pid1=running->PID;
QString time1_0=tr("%1").arg(time1);
QString priority1_0=tr("%1").arg(priority1);
ui->priorityPushButton->setText(priority1_0);
ui->timePushButton->setText(time1_0);
p->setText(running->PID+" "+time1_0+" "+priority1_0);
if(running->time<=0)
{
//在终止队列里添加元素
EnQueue(finishQueue,running->PID,0,running->priority,"finish");
//在终止队列视图中添加元素
EnRecord(model4,running->PID,0,running->priority,"finish");
running->PID="";
ui->priorityPushButton->setText("");
ui->timePushButton->setText("");
ui->pidPushButton->setText("");
p->setText("");
if(readyQueue.size>0)
{
qDebug()<<"readyQueue.size"<<readyQueue.size;
//从就绪队列中选取第一条数据插入
InsertIntoRunning();
//从waiting队列里选取一条数据插入就绪队列
InsertIntoReadyqueue();
}
else{
return;
}
return;
}
else if(running->time>0&&readyQueue.size>0) {
InsertIntoRunning();
qDebug()<<"执行完InsertIntoRunning()";
EnRecord(model2,pid1,time1,priority1,"ready");
EnQueue(readyQueue,pid1,time1,priority1,"ready");
return;
}
//即running.time>0而且就绪队列为空
else {
return;
}
}
}
}
//在这里进行更换手动还是自动进行处理机调度
void Widget::setValue()
{
if(ui->autoComboBox->currentText()=="自动调度")
{
time->start(2000);
}
if(ui->autoComboBox->currentText()=="手动调度")
{
time->stop();
}
}
//设置动画效果
void Widget::beginAnimation()
{
p->raise();
p->setVisible(true);
animation->setPropertyName("geometry");
animation->setDuration(1000);
animation->setStartValue(QRect(470,330,300,50));
animation->setEndValue(QRect(470,555,300,50));
animation->start();
}
- newPcb.cpp
//该文件表示新加进程界面
#include "newpcb.h"
#include "ui_newpcb.h"
#include<QStyleOption>
#include<QPainter>
#include<QBitmap>
NewPcb::NewPcb(QWidget *parent) :
QWidget(parent),
ui(new Ui::NewPcb)
{
ui->setupUi(this);
// widget=new Widget();这样有问题
//隐藏标题栏
setWindowFlags(Qt::FramelessWindowHint);//无边框 置顶
//设置样式
this->setStyleSheet("#Widget{background-color: rgba(255, 0, 0, 150);}");
}
void NewPcb::paintEvent(QPaintEvent *p1)
{
//绘制样式
QStyleOption opt;
opt.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);//绘制样式
QBitmap bmp(this->size());
bmp.fill();
QPainter painter(&bmp);
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::black);
painter.setRenderHint(QPainter::Antialiasing);
painter.drawRoundedRect(bmp.rect(), 12, 12);
setMask(bmp);
}
NewPcb::~NewPcb()
{
delete ui;
}
void NewPcb::on_okPushButton_clicked()
{
this->widget->show();
this->hide();
}
void NewPcb::on_returnPushButton_clicked()
{
this->widget->show();
this->hide();
}
void NewPcb::setWidget(Widget *widget)
{
this->widget=widget;
}
六、实验结论
在动态优先级调度算法当中可以让优先级高的首先得到执行,规定正在执行的进程,其优先权将随着执行时间的增加而逐渐降低,使其优先权可能不再是最高,从而暂停其执行,将处理器回收并分配给其他优先权更高的进程。这种方式能防止个别长期进程长期占用处理器的现象。但也会存在无穷等待的问题,可以用老化来解决。
在时间片轮转法,每次调度时把CPU分配给队首进程,让其执行一个时间片,当时间片用完,由计时器发出时钟中断,调度程序则暂停该进程的执行,使其退出处理器,并将它送到就绪队列的末尾,等待下一轮调度执行。然后,把CPU分配给就绪队列中新的队首进程,同时也让它执行一个时间片。这样就可以保证就绪队列中的所有进程,在一定的时间(可接受的等待时间)内,均能获得一个时间片的执行时间。但时间片的选择很重要
七、实验小结
- 该实验满足了实验要求中的所有内容,采用图形化界面,并加入了一些动画效果,使cpu调度过程看起来更加直观,引入数据库,可以保存上一次运行时未完成、挂起以及后备队列里的的进程,使其不会丢失,并且可以通过navicat对数据库进行可视化管理,方便使用。
- 通过这次试验,由于使用的是队列的数据结构,以前并不是很熟悉,通过这次的实验, 让我对队列的使用和指针的认识更加深刻;也让我对数据库的增删查改的使用更加熟 练,提高了我的编程能力
- 通过这次实验让我对处理机调度有了更加直观的认识,也让我意识到了优先级调度和时间片 轮转两种调度方式的各自优缺点,加深了解处理机调度的工作过程。