操作系统_进程调度模拟算法_附源码运行截图_C++

一、目的和要求

进程调度是处理机管理的核心内容。本实验要求用高级语言编写模拟进程调度程序,以便加深理解有关进程控制快、进程队列等概念,并体会和了解优先数算法和时间片轮转算法的具体实施办法。

二、实验内容

1.设计进程控制块PCB的结构,通常应包括如下信息:

    进程名、进程优先数(或轮转时间片数)、进程已占用的CPU时间、进程到完成还需要的时间、进程的状态、当前队列指针等。

  2.编写两种调度算法程序:

    优先数调度算法程序

    循环轮转调度算法程序

3.按要求输出结果。      

三、提示和说明

    分别用两种调度算法对伍个进程进行调度。每个进程可有三种状态;执行状态(RUN)、就绪状态(READY,包括等待状态)和完成状态(FINISH),并假定初始状态为就绪状态。

  (一)进程控制块结构如下:

      NAME——进程标示符

      PRIO/ROUND——进程优先数/进程每次轮转的时间片数(设为常数2)

      CPUTIME——进程累计占用CPU的时间片数

      NEEDTIME——进程到完成还需要的时间片数

      STATE——进程状态

      NEXT——链指针

    注:

    1.为了便于处理,程序中进程的的运行时间以时间片为单位进行计算;

    2.各进程的优先数或轮转时间片数,以及进程运行时间片数的初值,均由用户在程序运行时给定。

  (二)进程的就绪态和等待态均为链表结构,共有四个指针如下:

      RUN——当前运行进程指针

      READY——就需队列头指针

      TAIL—— 就需队列尾指针

      FINISH—— 完成队列头指针

(三)程序说明

    1. 在优先数算法中,进程优先数的初值设为:

      50-NEEDTIME

每执行一次,优先数减1,CPU时间片数加1,进程还需要的时间片数减1。

    在轮转法中,采用固定时间片单位(两个时间片为一个单位),进程每轮转一次,CPU时间片数加2,进程还需要的时间片数减2,并退出CPU,排到就绪队列尾,等待下一次调度。

    2. 程序的模块结构提示如下:

    整个程序可由主程序和如下7个过程组成:

    (1)INSERT1——在优先数算法中,将尚未完成的PCB按优先数顺序插入到就绪队列中;

    (2)INSERT2——在轮转法中,将执行了一个时间片单位(为2),但尚未完成的进程的PCB,插到就绪队列的队尾;

    (3)FIRSTIN——调度就绪队列的第一个进程投入运行;

    (4)PRINT——显示每执行一次后所有进程的状态及有关信息。

    (5)CREATE——创建新进程,并将它的PCB插入就绪队列;

    (6)PRISCH——按优先数算法调度进程;

    (7)ROUNDSCH——按时间片轮转法调度进程。

    主程序定义PCB结构和其他有关变量。

(四)运行和显示

    程序开始运行后,首先提示:请用户选择算法,输入进程名和相应的NEEDTIME值。

    每次显示结果均为如下5个字段:

      name   cputime   needtime   priority   state

    注:

    1.在state字段中,"R"代表执行态,"W"代表就绪(等待)态,"F"代表完成态。

    2.应先显示"R"态的,再显示"W"态的,再显示"F"态的。

    3.在"W"态中,以优先数高低或轮转顺序排队;在"F"态中,以完成先后顺序排队。


说明: 程序包含三种调度算法

        1、抢占式优先数调度算法

        2、非抢占式优先数调度算法

        3、时间片轮转法

//Lz毅

#include <iostream>
#include <string>
using namespace std;

typedef struct PCB
{
	string NAME = "";//进程名
	int PRIO_ROUND = 0;//进程优先数(或轮转时间片数)
	int CPUTIME = 0;//进程已占用的CPU时间
	int NEEDTIME = 0;//进程到完成还需要的时间
	string STATE = "";//进程的状态
	PCB* NEXT = NULL;//指向下一条的指针
}PCB;

PCB* RUN;//当前运行进程指针
PCB* READY;//就绪队列头指针
PCB* TAIL;//就绪队列尾指针
PCB* FINISH;//完成队列头指针
PCB* TAIL_F;//完成队列尾指针

PCB* create_pcb(int i, int flag)//PCB创建
{
	PCB* pcb = new PCB;
	cout << "请输入第" << i << "个进程名" << endl;
	cin >> pcb->NAME;
	cout << "请输入第" << i << "个进程需要时间" << endl;
	cin >> pcb->NEEDTIME;
	if (flag)//1表示优先
	{
		pcb->PRIO_ROUND = 50 - pcb->NEEDTIME;
	}
	else//0表示时间片轮转
	{
		pcb->PRIO_ROUND = 2;
	}
	pcb->STATE = "W";
	return pcb;
}
void readyadd(PCB* pcb)//ready队列添加
{
	PCB* s = pcb, * p, * q;//q记录p节点的前一个节点指针
	p = READY->NEXT;
	q = READY;
	while (p != NULL && (s->PRIO_ROUND <= p->PRIO_ROUND))//保证p有节点的情况下,让p指向的节点优先数小于s ,保证队列顺序与输入的顺序相同
	{
		q = p;
		p = p->NEXT;
	}
	//插入就绪队列里 插入到p前面
	s->NEXT = p;
	q->NEXT = s;
	if (s->NEXT == NULL)//新数据插入到了队尾,需要维护尾指针
	{
		TAIL = s;
	}
}

void run_to_ready_prio()//执行队列队头节点进入就绪队列,按照优先数从大到小排列
{
	PCB* s, * p, * q;//q记录p节点的前一个节点指针
	s = RUN->NEXT;
	RUN->NEXT = NULL;
	s->STATE = "W";
	p = READY->NEXT;
	q = READY;
	//保证p有节点的情况下,让p指向的节点优先数小于s ,即插入后与新节点优先级相同的节点在新节点前面 (只是较之前加了个等号)
	//这里考虑了由于程序没有 等待时优先级提升 的机制 同优先级下让等待时间长的程序排前面先执行(不知道是否合适)
	while (p != NULL && (s->PRIO_ROUND <= p->PRIO_ROUND))
	{
		q = p;
		p = p->NEXT;
	}
	//插入就绪队列里 插入到p前面
	s->NEXT = p;
	q->NEXT = s;
	if (s->NEXT == NULL)//新数据插入到了队尾,需要维护尾指针
	{
		TAIL = s;
	}
}

void ready_to_run_prio()//就绪队头节点放入运行队列 由于一个时间片只运行一个进程,所以运行队列同时只有一个进程节点,直接放到执行队列头结点后面作为队头节点
{
	RUN->NEXT = READY->NEXT;
	READY->NEXT = READY->NEXT->NEXT;
	RUN->NEXT->NEXT = NULL;
	RUN->NEXT->STATE = "R";
}

void run_and_ready_change_prio()//查找就绪队列中优先级最高的任务与当前运行的任务那个优先级高
{
	if (READY->NEXT == NULL)//就绪队列空 直接跳过,一直执行运行队列中的进程
	{
		return;
	}
	else if (RUN->NEXT == NULL)//运行队列为空 直接从就绪队列中调入队头节点
	{
		ready_to_run_prio();
	}
	else//全不为空 取两队列队头元素优先级 判读是否抢断
	{
		int ready_pri = READY->NEXT->PRIO_ROUND;//ready_pri就绪队列中的最大优先级进程的优先级,就绪队列按照优先级排序,队头即为最高者
		int run_pri = RUN->NEXT->PRIO_ROUND;//run_pri 执行的进程的优先级
		if (ready_pri > run_pri)//优先数大的先执行,为真表示抢断 将运行队列队头节点插入到就绪队列中,就绪队头节点放入运行队列
		{
			run_to_ready_prio();//运行队列队头节点插入到就绪队列中
			ready_to_run_prio();//就绪队头节点放入运行队列
		}
	}
}

void run_and_ready_change_prio_no()//非抢断 运行队列为空就将就绪队列队头放入运行队列里
{
	if (RUN->NEXT == NULL)
	{
		ready_to_run_prio();//就绪队头节点放入运行队列
	}
}

/*
在RR调度算法中,应在何时进行进程的切换,可分为两种情况:
①若一个时间片尚未用完,正在运行的进程便已经完成,就立即激活调度程序,将它从就绪队列中删除,再调度就绪队列中队首的进程运行,并启动一个新的时间片。
②在一个时间片用完时,计时器中断处理程序被激活。如果进程尚未运行完毕,调度程序将把它送往就绪队列的末尾。
*/
int ready_to_run_time()//就绪队列队头元素进入运行队列,返回使用的时间片数,最大为2
{
	READY->NEXT->STATE = "R";
	RUN->NEXT = READY->NEXT;
	READY->NEXT = READY->NEXT->NEXT;
	RUN->NEXT->NEXT = NULL;
	if (READY->NEXT == NULL)//维护尾指针 指向READY队列头结点 而不是RUN队列队头元素节点
	{
		TAIL = READY;
	}
	if (RUN->NEXT->NEEDTIME >= 2)//用完时间片
	{
		return 2;
	}
	else//两个时间片没用完,进程运行完毕,立即激活调度程序,启动一个新的时间片单位(两个时间片)
	{
		return 1;
	}
}

void into_ready_time()//执行队列任务进入就绪队列队尾
{
	RUN->NEXT->STATE = "W";
	TAIL->NEXT = RUN->NEXT;//维护队尾指针
	TAIL = TAIL->NEXT;
	RUN->NEXT = RUN->NEXT->NEXT;
}

void into_finsh()//执行队列队头节点进入完成队列队尾
{
	RUN->NEXT->STATE = "F";
	TAIL_F->NEXT = RUN->NEXT;
	RUN->NEXT = RUN->NEXT->NEXT;
	TAIL_F = TAIL_F->NEXT;//维护尾指针
	TAIL_F->NEXT = NULL;//节点移动之后不会把节点之后其他队列的节点也连接到完成队列上
}

void run_prio_pcb()//任务在执行队列进行的计算。如果需要时间等于0,放入完成队列队尾,否则仍放在运行队列中
{
	RUN->NEXT->CPUTIME += 1;
	RUN->NEXT->NEEDTIME -= 1;
	RUN->NEXT->PRIO_ROUND -= 1;
	if (RUN->NEXT->NEEDTIME <= 0)//如果需要时间小于等于0.放入完成队列
	{
		into_finsh();
	}
}

void run_time_pcb()//任务在执行队列进行的计算。如果需要时间等于0,放入完成队列,否则放入就绪的队列队尾
{
	if (RUN->NEXT->NEEDTIME >= 2)//能使用两个时间片
	{
		RUN->NEXT->CPUTIME += 2;
		RUN->NEXT->NEEDTIME -= 2;
	}
	else//用不完
	{
		RUN->NEXT->CPUTIME += 1;
		RUN->NEXT->NEEDTIME -= 1;
	}
	if (RUN->NEXT->NEEDTIME <= 0)//如果需要时间小于等于0.放入完成队列
	{
		into_finsh();
	}
	else//否则放入就绪队列队尾
	{
		into_ready_time();
	}
}
void show_all()//输出三个队列
{
	PCB* s = NULL;
	cout << "\"R\"态:" << endl;
	for (s = RUN->NEXT; s != NULL; s = s->NEXT)//输出运行队列
	{
		cout << "name:" << s->NAME << "    cputime:" << s->CPUTIME << "    needtime:" << s->NEEDTIME << "    priority:" << s->PRIO_ROUND << "    state:" << s->STATE << endl;
	}
	cout << "\"W\"态:" << endl;
	for (s = READY->NEXT; s != NULL; s = s->NEXT)//输出就绪队列
	{
		cout << "name:" << s->NAME << "    cputime:" << s->CPUTIME << "    needtime:" << s->NEEDTIME << "    priority:" << s->PRIO_ROUND << "    state:" << s->STATE << endl;
	}
	cout << "\"F\"态:" << endl;
	for (s = FINISH->NEXT; s != NULL; s = s->NEXT)//输出完成队列
	{
		cout << "name:" << s->NAME << "    cputime:" << s->CPUTIME << "    needtime:" << s->NEEDTIME << "    priority:" << s->PRIO_ROUND << "    state:" << s->STATE << endl;
	}
}
int main()
{
	PCB* pcb;
	int choice = 0;//选择算法
	int choice_2 = 0;//选择是否添加进程
	int num;//输入进程数量
	//初始化头指针
	RUN = new PCB;
	READY = new PCB;
	FINISH = new PCB;
	RUN->NEXT = NULL;
	READY->NEXT = NULL;
	FINISH->NEXT = NULL;
	//初始化尾指针
	TAIL = READY;
	TAIL_F = FINISH;
	cout << "请输入选择的算法:\n1.抢占式优先数调度算法\n2.非抢占式优先数调度算法\n3.循环轮转调度算法" << endl;
	cin >> choice;
	switch (choice)
	{
	case 1:
		cout << "请输入输入进程个数:" << endl;
		cin >> num;
		for (int i = 0; i < num; i++)
		{
			pcb = create_pcb(i + 1, 1);//1表示优先,0表示时间片轮转
			readyadd(pcb);//就绪队列添加任务
		}
		cout << "-----------------------------------初始状态-----------------------------------" << endl;
		show_all();
		for (int cs = 1; READY->NEXT != NULL || RUN->NEXT != NULL; cs++)//运行和就绪队列有一个不空就继续执行
		{
			//循环
			run_and_ready_change_prio();//调整运行队列和就绪队列的元素
			cout << "---------------------------- 执行第 " << cs << " 个时间片 ----------------------------" << endl;
			show_all();
			run_prio_pcb();//对进入执行队列的任务进行操作
		}
		cout << "----------------------------------- 执行结束 -----------------------------------" << endl;
		show_all();
		break;
	case 2:
		cout << "请输入输入进程个数:" << endl;
		cin >> num;
		for (int i = 0; i < num; i++)
		{
			pcb = create_pcb(i + 1, 1);//1表示优先,0表示时间片轮转
			readyadd(pcb);//就绪队列添加任务
		}
		cout << "-----------------------------------初始状态-----------------------------------" << endl;
		show_all();
		for (int cs = 1; READY->NEXT != NULL || RUN->NEXT != NULL; cs++)//运行和就绪队列有一个不空就继续执行
		{
			//循环
			run_and_ready_change_prio_no();//调整运行队列和就绪队列的元素
			cout << "---------------------------- 执行第 " << cs << " 个时间片 ----------------------------" << endl;
			show_all();
			run_prio_pcb();//对进入执行队列的任务进行操作
			cout << "\n请输入要执行的动作:\n1.继续执行一个时间片\n2.新增进程" << endl;
			do {
				cin >> choice_2;
				switch (choice_2)
				{
				case 1:
					break;
				case 2:
					cout << "请输入输入进程个数:" << endl;
					cin >> num;
					for (int i = 0; i < num; i++)
					{
						pcb = create_pcb(i + 1, 1);//1表示优先,0表示时间片轮转
						readyadd(pcb);//就绪队列添加任务
					}
					break;
				default:
					cout << "输入不正确,请重试" << endl;
					break;
				}
			} while (choice_2 != 1 &&choice_2 != 2);
		}
		cout << "----------------------------------- 执行结束 -----------------------------------" << endl;
		show_all();
		break;
	case 3:
		cout << "请输入输入进程个数:" << endl;
		cin >> num;
		for (int i = 0; i < num; i++)
		{
			pcb = create_pcb(i + 1, 0);//1表示优先,0表示时间片轮转
			readyadd(pcb);//就绪队列添加任务
		}
		cout << "-----------------------------------初始状态-----------------------------------" << endl;
		show_all();
		int x;
		for (int cs = 1; READY->NEXT != NULL || RUN->NEXT != NULL;)//运行和就绪队列有一个不空就继续执行
		{
			//循环
			x = ready_to_run_time();//查找优先级最高的任务
			cout << "-------------------------- 从第 " << cs << " 个时间片开始,执行 " << x << " 个时间片 --------------------------" << endl;
			cs += x;
			show_all();
			run_time_pcb();//对进入执行队列的任务进行操作
		}
		cout << "----------------------------------- 执行结束 -----------------------------------" << endl;
		show_all();
		break;
	default:
		cout << "输入不正确,请重试" << endl;
	}
	return 0;
}
/*
测试数据一:

1
5
A
5
B
8
C
10
D
1
E
8

测试数据二:

2
5
A
5
B
6
C
5
D
1
E
8
1
2
2
F
4
G
7
后为全1
测试数据三:

3
5
A
5
B
6
C
5
D
1
E
8

*/

运行截图(测试样例见代码末):

1、抢占式优先数调度算法:

2、非抢占式优先数调度算法:

 

3、时间片轮转法:


  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现了如下四种调度算法模拟: (1)时间片轮转调度 (2)优先数调度 (3)最短进程优先 (4)最短剩余时间优先 模拟过程使用了JProgressBar作为进程状态条,更为直观地观察到每个进程的执行状态。 程序用户说明: 1、在上图标号1处输入要创建随机进程的个数,仅可输入正数,非正数会有相关提示。然后点击标号2处的“创建进程”按钮,随进创建的进程显示在程序界面的中央窗口,如标号3所示。 2、创建好随机进程后,在标号4的单选框选择将要模拟执行的调度算法,然后点击标号5处的“开始模拟”,程序开始执行。标号3的列表会显示相应的调度变化。 3、模拟过程中,可以继续添加新的进程,操作同上。 4、 一个算法模拟执行完毕之后,可以点击标号6的“复位”按钮,可以重置列表的内容为程序模拟运行前的内容。复位成功后,可以继续选择其他调度算法进行模拟。 5、标号7显示为程序模拟过程中的时间,从1秒开始累计。 6、点击标号8的“清空”按钮,可以清空类别的进程,以便程序的下次执行。 题目要求: 题目四 单处理器系统的进程调度 一 、 课 程 设 计 目 的 1. 加深对进程概念的理解, 明确进程和程序的区别。 2. 深入了解系统如何组织进程、 创建进程。 3. 进一步 认识如何实现处理器调度。 二 、 课 程 设 计 内 容 编写程序完成单处理器系统中的进程调度, 要求实现时间片轮转、 优先数、 最短进程优 先和最短剩余时间优先四种调度算法实验具体包括: 首先确定进程控制块的内容, 进程控 制块的组成方式; 然后完成进程创建原语和进程调度原语; 最后编写主函数对所作工作进行 测试。 模拟程序只对你所设置的“ 虚拟 PCB” 进行相应的调度模拟操作, 即每发生“ 调度” 时, 显示出当前运行进程的“ 进程标识符”、“ 优先数”、“ 剩余运行时间” 等, 而不需要对系 统中真正的 PCB 等数据进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值