要求:书写课程设计报告,报告中应该包含如下内容:
(1)课程设计题目及内容
题目一:设计一个按照时间片轮转法实现处理机调度的程序
时间片轮转法实现处理机调度的程序设计提示如下:
(1)假设系统有n个进程,每个进程用一个进程控制块(PCB)来代表。进程控制块的格式如下表所示,且参数意义也相同。
(2)按照进程到达的先后顺序排成一个循环队列,设一个队首指针指向第一个到达进程的首址。另外再设一个当前运行进程指针,指向当前正运行的进程。
(3)执行处理机调度时,首先选择队首的第一个进程运行。
(4)由于本题目是模拟实验,所以对被选中的进程并不实际启动运行,而只是执行如下操作:1)估计运行时间减1;
2)输出当前运行进程的名字。
用这两个操作来模拟进程的一次运行。
(5)进程运行一次后,以后的调度则将当前指针依次下移一个位置,指向下一个进程,即调整当前运行指针指向该进程的链接指针所指进程,以指示应运行进程,同时还应判断该进程的剩余运行时间是否为0,若不为0,则等待下一轮的运行,若该进程的剩余运行时间为0,则将该进程的状态置为完成状态“C”,并退出循环队列。
(6)若就绪队列不为空,则重复上述的步骤(4)和(5)直到所有进程都运行完为止。
(7)在所设计的调度程序中,应包含显示或打印语句,以便显示或打印每次选中进程的名称及运行一次后队列的变化情况。
(2)程序中使用的数据结构及主要符号说明
int PCBNum; //总进程数
#define Maxsize 50 //最大进程数
int t_time = 0; //系统时间
typedef struct PNode
{
char name[10]; //定义进程名,并分配空间
int Arr_Time; //定义到达时间
int ready_Time; //定义运行时间
char state; //定义进程状态R(就绪)/F(运行)/C(完成)
}PNode;
typedef struct
{
PNode *data;
PNode* ready;
int datafront, datarear; //数据存储队列队首队尾
int readyfront, readyrear; //就绪队列队首队尾
}SqPCB;
(3)程序流程图和带有注释的源程序
程序流程图:
源程序:
#include<iostream>
#include<time.h>
#include<string>
#include<string.h>
using namespace std;
int PCBNum; //总进程数
#define Maxsize 50 //最大进程数
int t_time = 0; //系统时间
typedef struct PNode
{
char name[10]; //定义进程名,并分配空间
int Arr_Time; //定义到达时间
int ready_Time; //定义运行时间
char state; //定义进程状态R(就绪)/F(运行)/C(完成)
}PNode;
typedef struct
{
PNode *data;
PNode* ready;
int datafront, datarear; //数据存储队列队首队尾
int readyfront, readyrear; //就绪队列队首队尾
}SqPCB;
void lnitPCB(SqPCB& H)//初始化就绪队列
{
cout << "请输入总进程个数:";
cin >> PCBNum; ///进程总个数
cout << endl;
int Num = PCBNum;
H.datafront = 0; //初始化数据存储队列队首
H.datarear = 0; //初始化数据存储队列队尾
H.readyfront = 0; //初始化就绪队列队首
H.readyrear = 0; //初始化就绪队列队尾
H.data = (PNode*)malloc(Maxsize * sizeof(PNode));
H.ready = (PNode*)malloc(Maxsize * sizeof(PNode));
char ch[10] = { 'A' };
PNode p;
srand((unsigned)time(NULL));
cout << "总进程个数为" << PCBNum << "个,请输入各个进程的名字(由于是模拟程序,到达时间和运行时间由随机数生成)" << endl;
while (Num--)
{
strcpy_s(p.name, ch);
ch[0] = ch[0] + 1;
p.Arr_Time = rand() % 8 + 1;
p.ready_Time = rand() % 10 + 1;
p.state = 'R';
H.data[H.datarear] = p;
H.datarear = (H.datarear + 1) % Maxsize;
}
cout << endl;
}
void show(SqPCB& H)
{
cout << "进程信息" << endl;
int i = H.datafront;
while(i!=H.datarear)
{
cout << "进程名:" << H.data[i].name
<< "\t到达时间:" << H.data[i].Arr_Time
<< "\t运行时间:" << H.data[i].ready_Time
<< "\t进程状态:" << H.data[i].state << endl;
i = (i + 1) % Maxsize;
}
cout << endl;
}
void showready(SqPCB& H)//打印就绪队列
{
cout << "就绪队列内进程信息(按处理机调度顺序)" << endl;
int i = H.readyfront;
if (H.readyfront == H.readyrear)
{
cout << "就绪队列为空!!!";
}
while (i != H.readyrear)
{
cout << "进程名:" << H.ready[i].name
<< "\t到达时间:" << H.ready[i].Arr_Time
<< "\t运行时间:" << H.ready[i].ready_Time
<< "\t进程状态:" << H.ready[i].state << endl;
i = (i + 1) % Maxsize;
}
cout << endl;
}
void sort(SqPCB& H)
{
for (int i = 0; i < PCBNum; i++)
{
for (int j = 0; j < PCBNum - 1 - i; j++)
{
if (H.data[j].Arr_Time > H.data[j + 1].Arr_Time)
{
PNode temp;
strcpy(temp.name, H.data[j].name);
temp.Arr_Time = H.data[j].Arr_Time;
temp.ready_Time = H.data[j].ready_Time;
strcpy(H.data[j].name, H.data[j + 1].name);
H.data[j].Arr_Time = H.data[j+1].Arr_Time;
H.data[j].ready_Time = H.data[j+1].ready_Time;
strcpy(H.data[j+1].name, temp.name);
H.data[j + 1].Arr_Time = temp.Arr_Time;
H.data[j+1].ready_Time = temp.ready_Time;
}
}
}
cout << "***********************************************************************" << endl;
cout << "排序之后的进程运行顺序:" << endl;
show(H);
}
void SJP_Simulator(SqPCB& H)
{
int* flag = new int[PCBNum];
int x = 0;
int o = H.datarear - H.datafront;
while (x!=PCBNum)//如果进程都执行完毕则结束循环
{
while (o)//判断是否有新的进程同时到达
{
if (t_time >= H.data[H.datafront].Arr_Time && H.datafront != H.datarear)//判断是否有新的进程到达
{
flag[H.datafront] = 1;
PNode temp;
strcpy(temp.name, H.data[H.datafront].name); //就绪队列入队
temp.Arr_Time = H.data[H.datafront].Arr_Time; //用temp结点存储数据
temp.ready_Time = H.data[H.datafront].ready_Time;
temp.state = H.data[H.datafront].state;
H.ready[H.readyrear] = temp; //进程进入就绪队列队尾
H.readyrear = (H.readyrear + 1) % Maxsize; //队尾后移
H.datafront++; //数据存储队列队首后移
}
o--;
}
o = H.datarear - H.datafront;
if (H.readyfront != H.readyrear)//就绪队列不为空
{
if (H.ready[H.readyfront].ready_Time != 1)
{
cout << "--------------------------------系统时间为:" << t_time << "---------------------------------------" << endl;
cout << "当前运行的进程为:" << H.ready[H.readyfront].name << endl;
cout << "该进程时间片用完后运行时间由" << H.ready[H.readyfront].ready_Time << "变为" << H.ready[H.readyfront].ready_Time - 1 << endl;
H.ready[H.readyfront].ready_Time--;//运行时间-1
H.ready[H.readyfront].state = 'F';//更改进程状态为运行状态"F"
showready(H);
H.ready[H.readyfront].state = 'R';//运行完之后更改进程状态为就绪状态"R"
H.ready[H.readyrear] = H.ready[H.readyfront]; //将运行完之后的进程插入就绪队列队尾
H.readyrear = (H.readyrear + 1) % Maxsize; //就绪队列队尾后移
H.readyfront = (H.readyfront + 1) % Maxsize; //就绪队列队首后移
}
else if (H.ready[H.readyfront].ready_Time == 1)
{
cout << "--------------------------------系统时间为:" << t_time << "---------------------------------------" << endl;
cout << "当前运行的进程为:" << H.ready[H.readyfront].name << endl;
cout << "该进程时间片用完后运行时间由" << H.ready[H.readyfront].ready_Time << "变为" << H.ready[H.readyfront].ready_Time - 1 << endl;
cout << "进程" << H.ready[H.readyfront].name << "执行完毕!!" << endl;
x++;
H.ready[H.readyfront].state = 'C';//进程状态置为完成状态"C"
H.ready[H.readyfront].ready_Time--;//运行时间-1
showready(H);
H.readyfront = (H.readyfront + 1) % Maxsize; //令该进程出队
}
}
else
{
cout << "--------------------------------系统时间为:" << t_time << "---------------------------------------" << endl;
showready(H);
}
t_time++;//系统时间+1
}
cout << "--------------------------------全部进程运行完毕!!--------------------------------" << endl;
}
int main()
{
SqPCB A;
lnitPCB(A); //数据初始化
show(A); //打印
sort(A); //排序
SJP_Simulator(A); //时间片轮转法
}
(4)执行程序,并打印程序运行时的初值和运算结果
运行程序,输入总进程个数,程序自动模拟生成进程信息
结果进程全部运行成功
(5)实验结果分析,实验收获和体会
进程信息系统模拟生成后会按照到达时间进行排序
当系统时间为0时,没有进程到达,此时就绪队列为空
当系统时间为1时,进程B到达,将进程C调入处理器运行,进程状态更改为‘F’(运行中),运行时间减1,运行完进程状态更改为‘R’(就绪)后调入就绪队列队尾,
当系统时间为3时,进程G到达,将进程G调入就绪队列队尾,此时队首为进程B,所以进程B调入处理器运行,进程状态更改为‘F’,运行时间减1,运行完后进程状态更改为‘R’(就绪)调入就绪队列队尾
当系统时间为4时,此前因为进程B运行完,调入就绪队列队尾,进程E到达,将进程E调入就绪队列队尾,此时队首为进程G,将进程G调入处理器运行,进程状态更改为‘F’,运行时间减1,运行完进程状态更改为‘R’(就绪)后调入就绪队列队尾
当系统时间为10时,进程E运行时间减为0后,进程E运行完毕,将进程E的进程状态更改为‘C’(完成),然后将其调出队列
当最后一个进程运行完毕后,全部进程运行完毕
收获和体会:
通过这次实验,加深了对时间片轮法的理解,对于就绪态,运行态的转换的认识更加深刻,同时对于数据结构队列的知识又复习了一遍,实验中出现了许多问题,如数组越界,内存泄漏,字符串string类的使用,对于这些问题又重新温习了一边,对于C++的使用更加熟练了。