操作系统进程调度算法
1 题目描述
1.1 实验目的
用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。
1.2 实验内容
编写并调试一个模拟的进程调度程序,采用简单时间片轮转法”调度算法对五个进程进行调度。
每个进程有一个进程控制块(PCB)表示.进程控制块可以包含如下信息:进程名、到达时间、需要
运行时间、已运行时间、进程状态等等。
进程的到达时间及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。进程的运行时间以时间片为单位进行计算。
每个进程的状态可以是就绪W(Wait)、运行R(Run)两种状态之一。
就绪进程获得CPU后都只能运行一个时间片。用运行时间加1来表示。
如果运行一个时间片后,进程的已占用CPU时间已达到所需要的运行时间,则撤消该进程,如果运行
一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应分配时间片给就绪队列中排在该进程之后的进程,并将它插入就绪队列队尾。每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的PCB,以便进行检查。
重复以上过程,直到所要进程都完成为止。
1.3 实验步骤
(1)按先来先服务算法将进程排成就绪队列。
(2)检查所有队列是否为空,若空则退出,否则将队首进程调入执行。
(3)检查该运行进程是否运行完毕,若运行完毕,则撤消进程,否则,将该进程插入到下一个逻辑队列的队尾。
(4)是否再插入新的进程若是则把它放到第一逻辑队列的列尾。
(5)重复步骤(2)、(3)、(4),直到就绪队列为空。
2 代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<time.h>
#include<queue>
#include<Windows.h>
using namespace std;
const int MAX = 10;//最大进程数
const int RANDOM_NAME_LEN = 5;//随机生成的进程名的长度
const int DEFAULT_NUM = -1e9; //用来判断是否已经赋值的数字
int pcbNum = DEFAULT_NUM; //实际进程个数
float timeSliceLen = 0;//时间片长度
char* randomName();//随机名称生成
int timeSpliceNum;//已经使用的时间片的数量
char addFlag;//标志是否需要中途插入进程
void outPutPCB();//输出PCB
void outPutQueue();//输出队列
void setPCB();//设置进程队列
void runPCB();//进程运行
void addPCB();//插入进程
void DynamicOutput(const char*, int);//动态输出语句
struct PCB {
char name[10]; //进程名称
float arriveTime; //到达时间
float needTime; //需要运行时间
float runTime; //已运行时间
char state; //进程状态
};
queue<PCB> waitQueue;/*进程就绪队列*/
queue<PCB> finishQueue;/*进程完成队列*/
PCB pcb[15];
/*自定义sort排序规则,根据到达时间进行排序*/
bool cmp(PCB p1, PCB p2) {
return p1.arriveTime < p2.arriveTime;
}
/*设置进程队列*/
void setPCB() {
printf("请输入任务个数\n");
do {
if (pcbNum != DEFAULT_NUM)printf("任务数只能为1~10,请重新输入!\n");
scanf("%d", &pcbNum);
} while (pcbNum > 10 || pcbNum <= 0);
printf("请输入时间片的长度\n");
scanf("%f", &timeSliceLen);
printf("输入1自动生成PCB,输入0则手动输入\n");
int f;
scanf("%d", &f);
DynamicOutput("\n是否需要中途插入进程,输入0为否\n", 50);
scanf("%d", &addFlag);
srand((unsigned)time(NULL));//随机数重置
int i;
for (i = 1; i <= pcbNum; i++)
{
if (f) {//随机生成进程名称、到达时间与需要的时间
strcpy(pcb[i].name, randomName());
pcb[i].arriveTime = 0.001 * (rand() % 100000);
pcb[i].needTime = 0.001 * (rand() % 100000);
}
else {
printf("\n[%d]请输入进程的名称、到达的时间、需要运行的时间:(中间用空格隔开)\n", i);
scanf("%s %f %f", pcb[i].name, &pcb[i].arriveTime, &pcb[i].needTime);
}
pcb[i].runTime = 0;//初始化运行时间
pcb[i].state = 'W';//设为就绪状态
}
sort(pcb+1, pcb + pcbNum+1, cmp);//对进程队列进行排序,优先到达的放在前面
for (int j = 1; j <= pcbNum; j++) {
waitQueue.push(pcb[j]);//将排序好的进程放入就绪队列
}
}
/*生成随机名称*/
char* randomName() {
char* str = (char*)malloc(RANDOM_NAME_LEN + 1);
char randomC;
int i = 0;
while (i < RANDOM_NAME_LEN) {
randomC = rand() % 26 + 'A';
str[i++] = randomC;
}
str[i] = '\0';
return str;
}
/*输出PCB*/
void outPutPCB() {
printf("\n================================PCB===================================\n");
printf("进程名称\t到达时间\t需要运行时间\t已运行时间\t进程状态\n");
for (int i = 1; i <= pcbNum; i++) {
printf("%s\t\t%5.3f\t\t%5.3f\t\t%5.3f\t\t %c\n", pcb[i].name, pcb[i].arriveTime, pcb[i].needTime, pcb[i].runTime, pcb[i].state);
}
}
/*输出队列*/
void outPutQueue() {
queue<PCB> WQ = waitQueue;
queue<PCB> FQ = finishQueue;
printf("\n就绪队列:");
while (!WQ.empty()) {
PCB p = WQ.front();
WQ.pop();
printf("%s\t", p.name);
}
printf("\n已完成队列:");
while (!FQ.empty()) {
PCB p = FQ.front();
FQ.pop();
printf("%s\t", p.name);
}
printf("\n");
}
/*进程运行*/
void runPCB() {
printf("\n\n开始运行...\n\n");
if (waitQueue.empty())printf("空");
while (!waitQueue.empty()) {
timeSpliceNum++;//记录已经使用的时间片的数量
PCB p = waitQueue.front();
p.state = 'R';
int i;
waitQueue.pop();
if (p.needTime - p.runTime >= timeSliceLen) {//如果当前进程还需要的时间大于或等于一个时间片
p.runTime += timeSliceLen;
}
else {//时间片长度大于当前进程还需要的时间(该时间片使用完后释放)
p.runTime = p.needTime;
}
for (i = 1; i <= pcbNum; i++) {//更新pcb
if (strcmp(p.name, pcb[i].name) == 0) {
pcb[i].state = p.state;
pcb[i].needTime = p.needTime;
pcb[i].runTime = p.runTime;
break;
}
}
outPutPCB();//输出pcb
if (p.runTime >= p.needTime) {//如果运行时间大于等于需要运行的时间,则说明已完成
//已经完成的进程,回收pcb
pcb[i] = pcb[pcbNum];
pcb[pcbNum] = p;
pcbNum--;
//放入进程完成队列
finishQueue.push(p);
}
else {//未完成,放入就绪队列队尾
pcb[i].state = 'W';
p.state = 'W';
waitQueue.push(p);
}
outPutQueue();//输出就绪与已运行队列
if (addFlag) {
printf("输入1可增加进程,输入0不增加,输入2则取消插入进程的功能(进程运行到底)\n");
int f;
scanf("%d", &f);
if (f == 2)addFlag = 0;
else if (f && f != 2)addPCB();
}
}
DynamicOutput("\n\n...进程运行完毕,再见!\n\n\n", 100);
}
/*插入进程*/
void addPCB() {
printf("输入1自动生成PCB,输入0则手动输入\n");
int f;
scanf("%d", &f);
pcbNum++;
if (f) {//随机生成进程名称、到达时间与需要的时间
strcpy(pcb[pcbNum].name, randomName());
pcb[pcbNum].needTime = 0.001 * (rand() % 100000);
}
else {
printf("\n请输入进程名称、运行时间:(中间用空格隔开)\n");
scanf("%s%f", pcb[pcbNum].name, &pcb[pcbNum].needTime);
}
pcb[pcbNum].arriveTime = pcb[pcbNum - 1].arriveTime + timeSpliceNum * timeSliceLen;//插入的进程的到达时间为:队列中最后一个进程的到达时间+当前程序已花费的时间
pcb[pcbNum].runTime = 0;//初始化运行时间
pcb[pcbNum].state = 'W';//设为就绪状态
waitQueue.push(pcb[pcbNum]);//将新增的进程放入就绪队列
}
/*动态输出欢迎语*/
void DynamicOutput(const char* str, int intervalIime) {
int i = 0;
while (str[i] != '\0') {
printf("%c", str[i++]);
if (str[i] != '\t' && str[i] != '\n') Sleep(intervalIime);//每输出一个字符进行休眠,从而实现动态输出效果(跳过\t和\n)
}
}
int main()
{
system("color a");//设置窗口背景与字体颜色
DynamicOutput("\n\t\t欢迎使用进程调度程序,请根据提示进行操作。\n\n", 100);//欢迎语
setPCB();//设置进程
runPCB();//运行进程
return 0;
}