操作系统进程调度算法,进程调度实验

操作系统进程调度算法

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;
}

3 运行结果

在这里插入图片描述

  • 14
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
(1)、假定系统有五个进程,每一个进程一个进程控制块PCB来代表。进程控制块的格式 (2)、每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“要求运行时间”。 把五个进程按顺序排成循环队列,用指针指出队列连接情况。另用一标志单元记录轮到运行进程。 (3)、处理器调度总是选择标志单元指示的进程运行。由于本实验是模拟处理器调度的功能,所以,对被选中的进程并不实际启动运行 (4)、进程运行一次后,应把该进程进程控制块中的指针值送到标志单元,以指示下一个轮到运行进程。同时,应判断该进程的要求运行时间与已运行时间,若该进程要求运行时间≠已运行时间,则表示它尚未执行结束,应待到下一轮时再运行。若该进程的要求运行时间=已运行时间,则表示它已经执行结束,应把它的状态修改为“结束”(E)且退出队列。此时,应把该进程进程控制块中的指针值送到前面一个进程的指针位置。 (5)、若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。 (6)、在所设计的称序中应有显示或打印语句,能显示或打印每次被选中进程进程名以及运行一次后进称对列的变化。 (7)、为五个进程任意确定一组“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程进程名以及进程控制块的动态变化过程。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰咖啡iii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值