题目一:设计一个按照时间片轮转法实现处理机调度的程序
1、时间片轮转法实现处理机调度的程序设计提示如下:
(1) 假设系统有n个进程,每个进程用一个进程控制块(PCB)来代表。进程控制块的格式如下表所示,且参数意义也相同。
(2) 按照进程到达的先后顺序排成一个循环队列,设一个队首指针指向第一个到达进程的首址。另外再设一个当前运行进程指针,指向当前正运行的进程。
(3) 执行处理机调度时,首先选择队首的第一个进程运行。
(4) 由于本题目是模拟实验,所以对被选中的进程并不实际启动运行,而只是执行如下操作:
1)估计运行时间减1;
2)输出当前运行进程的名字。
用这两个操作来模拟进程的一次运行。
(5) 进程运行一次后,以后的调度则将当前指针依次下移一个位置,指向下一个进程,即调整当前运行指针指向该进程的链接指针所指进程,以指示应运行进程,同时还应判断该进程的剩余运行时间是否为0,若不为0,则等待下一轮的运行,若该进程的剩余运行时间为0,则将该进程的状态置为完成状态“C”,并退出循环队列。
(6) 若就绪队列不为空,则重复上述的步骤(4)和(5)直到所有进程都运行完为止。
(7) 在所设计的调度程序中,应包含显示或打印语句,以便显示或打印每次选中进程的名称及运行一次后队列的变化情况。
2、程序流程图
3、程序实现
Test_data.h
#pragma once
#include<iostream>
#include<fstream>
#include <time.h>
using namespace std;
void data()//生成测试数据
{
int p;//进程的个数
int temp;//生成的随机数
ofstream outfile;//写文件对象
outfile.open("D:/C++/Processor_dispatch/data.txt", ios::out);
if (outfile.fail())//打开文件失败
{
cout << "file open fail!" << endl;
exit(0);
}
srand((unsigned int)time(NULL));//随机数种子
p= rand() % 10+1;//随机生成测试数据的组数
for (int i = 0; i < p; i++)
{
outfile<< i <<" ";
temp = rand() % 30+1;//到达时间
outfile << temp <<" ";
temp = rand() %10+1;//估计运行时间
outfile << temp <<" ";
outfile << "R" << endl;//进程就绪
}
outfile <<"end";//给数据结束做一个标记
outfile.close();//写文件结束
}
Processor_dispatch.cpp
#define NO_WARNINGS_
#include <iostream>
#include<fstream>
#include<string>
#include<sstream>
#include"Test_data.h"
using namespace std;
//进程控制块(PCB)
struct PCB
{
string process_name;//进程名
int arrival_time;//到达时间
int run_time;//预计运行时间
char process_status;//进程状态
struct PCB* next;//链接指针
};
int main()
{
data();
int counter = 1;//计时器
PCB* first=NULL;//队首指针
PCB* last = NULL;//队尾指针
PCB* present=NULL;//当前运行进程指针
PCB* temp=NULL;//临时指针
PCB* ready = NULL;//指向就绪队列的队首
string s;//每读取文件中的一行内容放在s
ifstream infile;//读文件对象
infile.open("D:/C++/Processor_dispatch/data.txt");//打开文件,导入数据
if (infile.fail())//文件打开失败
{
cout << "file open file!" << endl;
exit(0);
}
PCB first_node;//头结点
first_node.next = NULL;
first = &first_node;
while (!infile.eof())//初始化队列并排序(单向队列)
{
getline(infile, s);//每次读取一行
if (s != "end")//初始化
{
temp = new PCB();//为每个进程配置一个PCB
stringstream ss(s);//以空格为分隔符将一行字符分开,存放在ss中
ss >>temp->process_name;//依次为PCB赋值
ss >> temp->arrival_time;
ss >> temp->run_time;
ss >> temp->process_status;
/*处于就绪状态的进程,并按到达时间进行排序*/
if (first->next == NULL)//当队列为空时
{
temp->next = first->next;
first->next = temp;
last = temp;
}
else//当队列里有数据时
{
if (temp->arrival_time < first->next->arrival_time)//当前进程到达时间最早
{
temp->next = first->next;
first->next = temp;
}
else//当前进程到达时间稍晚
{
present = first->next;
while ( present->next !=NULL &&temp->arrival_time >= present->next->arrival_time)
present = present->next;
temp->next = present->next;
present->next = temp;
if (present == last)//插到队列的最后
last = present->next;
}
}
}
}
infile.close();//读文件操作结束
//temp = first;//当前temp所指向的内存不能用delete来释放,该内存由系统自己管理
//delete temp;//内存释放问题,结构变量由系统自己释放,即非new的内存都由系统释放
first = first->next;//单向队列变环形队列,first指针指向第一个到达的进程
if(last!=NULL)
last->next = first;
present = first;
temp = first;//输出排序后的序列
cout<<"*******初始数据******"<<endl;
while (temp->next != first)//输出初始化数据
{
cout << temp->process_name << " " << temp->arrival_time << " "<<temp->run_time<<" "<<temp->process_status<<endl;
temp = temp->next;
}
cout << temp->process_name << " " << temp->arrival_time << " " << temp->run_time << " " << temp->process_status << endl;
while (first->run_time > 0)//进程运行,时间片轮转
{
if (first->arrival_time<counter)//当前就绪队列是否为空
{
if (present->arrival_time >=counter)
{
temp = present;
while (temp->next != present)//转到运行当前第一个就绪进程
{
if (temp->next->arrival_time < counter)
break;
temp = temp->next;
}
last = temp;
present = last->next;//当前要执行的进程
temp = present;
cout << "时刻" << counter << " ";
while (temp->next != present)//输出就绪进程队列
{
if (temp->arrival_time <counter)
cout << temp->process_name;
temp = temp->next;
}
if (temp->arrival_time < counter)
cout << temp->process_name;
}
else
{
ready= present;
if(ready->next != present)//判断队列中进程个数是否只有一个
{
if (ready->next->arrival_time<=counter)//判断当前有无可能有进程抵达
{
while (ready->next->arrival_time < counter&&ready->next!=present)//寻找第一个抵达进程的上一个
ready = ready->next;
temp = ready; //记录第一个抵达进程的上一个
while (ready->next->arrival_time == counter && ready->next != present)//寻找最后一个抵达的进程
ready = ready->next;
if (temp != ready)//判断是否有进程抵达
{
if (ready == last);//有进程抵达,但队列里只有当前要运行的进程和抵达的进程,所以不做任何改变
else//将抵达的进程插入到适当的位置
{
last->next = temp->next;
temp->next = ready->next;
ready->next = present;
last = ready;
}
}
}
}
temp = present;
cout << "时刻"<<counter<<" ";
while (temp->next != present)//输出就绪进程队列
{
if (temp->arrival_time <counter)
cout << temp->process_name;
temp = temp->next;
}
if (temp->arrival_time < counter)
cout << temp->process_name;
}
present->run_time--;//运行时间-1
if (present->run_time > 0)
{
cout <<"\t\t"<<"进程" << present->process_name << '\t'<<"剩余运行时间:" << present->run_time << endl;
last = present;
}
else//该进程运行完毕
{
present->process_status = 'C';//修改进程状态
cout <<"\t\t" <<"******进程" << present->process_name << "运行完毕!******" << endl;
cout << endl;
if (present == first)//队首进程运行完毕
{
if (last == first)//队列中进程只剩一个
{
delete present;//释放该进程的内存空间
break;//进程调度结束
}
last->next = present->next;//修改 first 指针指向的进程
first = last->next;//first 默认指向队列中的下一个进程
temp = first;
while (temp->arrival_time >= counter)
{
if (temp->next == first)//寻找了一轮没找到有就绪进程
break;
else
temp = temp->next;
}
if (temp->arrival_time < counter)//找到一个就绪进程,修改first的指向
first = temp;
}
else
last->next = present->next;
delete present;//释放该进程的内存空间
}
present = last->next;
}
counter++;
}
}
重要变量及结构说明:
循环队列: 起初进程按到达时间加入队列,然后每次根据当前的时刻依次将当前到达的进程插入到就绪进程的队尾,即当前要运行的进程的上一个进程的尾部(抵达进程优于完成进程)。依次循环运行就绪进程,直至所有进程运行完毕。同时,其有插入和删除操作,以便相关进程的运行与退出。
first指针: 是判断该循环队列中当前有无就绪进程的关键标记,first 指针会随着当前first进程运行完毕而做出相应的改变,即它总是会找到一个就绪进程作为队首进程或找到未来最先抵达的进程作为队首进程。
ready指针: 用于输出当前的就绪进程队列,每次初始指向当前要运行的进程。然后循环寻找就绪进程,并输出(即到达时刻<当前时刻的进程)。
present指针: 指向当前要运行的进程的进程,不一定是当前进程运行完的下一个就绪进程,其值一般是当前运行进程链接的下一个进程。然后再通过循环查找下一个就绪进程。
计时器counter 用于记录当前的时刻,便于知道当前时刻的就绪进程队列是什么?当前时刻的运行进程是什么?有无当前时刻到达的进程?
4、程序运行结果
5、注意事项
读写文件的对象要自己创建,然后将创建后文件所在的地址替换掉给出代码中的地址即可。