操作系统实验:处理器调度 (C语言实现) 选择一个调度算法,实现处理器调度

一.实验内容

选择一个调度算法,实现处理器调度。本次实验选择【按优先数调度算法】完成。


二.实验题目

设计一个按优先数调度算法实现处理器调度的进程。

[提示]:

(1) 假定系统有五个进程,每一个进程用一个进程控制块 PCB 来代表。进程控制块的格 式为:

 其中,进程名----作为进程的标识,假设五个进程的进程名分别是 P1,P2,P3,P4,P5。

指针----按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块 首地址,最后一个进程中的指针为“0”。

要求运行时间----假设进程需要运行的单位时间数。

优先数----赋予进程的优先数,调度时总是选取优先数大的进程先执行。

状态----可假设有两种状态,“就绪”状态和“结束“状态,五个进程的初始状态都为 “就绪“状态,用“R”表示,当一个进程运行结束后,它的状态变为“结束”, 用“E”表示。

(2) 在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数” 和“要求运行时间”。

(3) 为了调度方便,把五个进程按给定的优先数从大到小连成队列,用一单元指出队首 进程,用指针指出队列的连接情况。

(4) 处理器调度总是选队首进程运行。采用动态改变优先数的办法,进程每运行一次优 先数就减“1”。由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的 启动运行,而是执行:

※优先数-1

※要求运行时间-1

来模拟进程的一次运行。

提醒注意的是:在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场, 它占有处理器运行,直到出现等待事件或运行结束。在这里省去了这些工作。

(5) 进程运行一次后,若要求运行时间≠0,则再将它加入队列(按优先数大小插入,且 置队首标志);若要求运行时间=0,则把它的状态修改为“结束”(E),且退出队列。

(6) 若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进 程都成为“结束”状态。

(7) 在所设计的称序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以 及运行一次后进称对列的变化。

(8) 为五个进程任意确定一组“优先数”和“要求运行时间”,启动所设计的处理器调度 程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。


三.代码实现

运行前先按提示输入五块PCB的runtime(运行时间)和pri(优先数),之后程序将自动调度执行并打印每次运行后各PCB块的信息。

#include <stdio.h>
#include<string.h>

#define MAX 5 //定义最大PCB数

struct PCB {
	int ID; //进程名称
	int runtime;//当前进程要求运行时间
	int pri;//优先等级  当两个进程pri相同时,ID小的先执行
	char state;//进程当前状态 E:结束 R:就绪 r:正在执行
};
struct PCB program[MAX];

void show_all()//打印所有PCB信息
{
	int i;
	printf("-------------------\n");
	for (i = 0; i < MAX; i++)
	{
		printf("ProgramID:%d\n", i);
		printf("Runtime:%d\n", program[i].runtime);		
		printf("Pri:%d\n", program[i].pri);
		printf("States:%c\n\n", program[i].state);

	}
	printf("-------------------\n");
}

void initPCB() //初始化各PCB进程数据
{
	int i = 0;
	for (i = 0; i < MAX; i++)
	{
		program[i].ID = i;
		program[i].state = 'R';//设置当前PCB的state为就绪态
		printf("请依次设置第%d块PCB的runtime和pri:",i+1);
		scanf("%d%d",&program[i].runtime,&program[i].pri);
		getchar();//吸收多余换行符
	}
}
int find_key() //寻找当前Pri最大的PCB下标值 
{
	int key=0; //存储找到Pri最大的下标值
	int i=0;
	int max_pri=-999;//当前最大的Pri值,默认值为-999
	for (i = 0; i < MAX; i++)  //循环找key值
	{
		if (program[i].state == 'r')  //正在运行
		{
			return -1;
		}
		else
		{
			if (program[i].pri > max_pri&&program[i].state == 'R')
			{
				max_pri = program[i].pri; //更新最大pri值
				key = i;//保存key值用于判断
			}
		}
	}		
	if (program[key].state == 'E')  //key对应PCB块已执行完
		{
			return -1;
		}
		else
		{
			return key; //成功返回key值
		}
}

void run_program()  //进程运行程序
{
	int t = 0;//表示需要运行的总次数
	int i = 0, j = 0;
	int count = 0;//计数器
	for (j = 0; j < MAX; j++)  
	{
		t = t + program[j].runtime; //计算总共需要运行的次数
	}
	printf("初始化后PCB块情况:\n");
	show_all();  
	for (j = 0; j < t; j++) //控制总运行次数,总次数为t
	{
		while (find_key() != -1)  //成功找到符合条件的Pri最大的PCB块
		{
			{
				program[find_key()].state = 'r';//将对应PCB块的state设置为运行态r
			}
			for (i = 0; i < MAX; i++) //i负责控制寻找第j次运行时state为r的PCB块
			{
				if (program[i].state == 'r')  //执行run操作--模拟进程执行
				{
					program[i].pri = program[i].pri - 1;
					program[i].runtime = program[i].runtime - 1;
					count++;
					{
						if (program[i].runtime == 0)  //若该次运行后该PCB的runtime已为0,则置其state为F
						
							program[i].state = 'E';
						else
							program[i].state = 'R';
					}	
					printf("第%d运行后各PCB块情况:\n",count);
					show_all();
				}

			}//for循环-i
		}//while循环				
	}//for循环-j
}

void main()
{
	initPCB(); //初始化
	run_program(); //运行程序
	printf("--------------------分 割 线------------------------\n");
	printf("运行后各PCB状态:\n");
	show_all();
	system("pause");
}

四.运行结果

1.设置各PCB块的初始数据

2. 执行run_program()函数

由1.中各PCB块的runtime数值之和可知,模拟run将运行16次后结束。截取部分运行代码.

 3.程序执行结束

当16次模拟run执行完后,最后一次打印各PCB块的参数时可看到,所有PCB的runtime均为0并且states均为E(end)。


 五.流程图

1.find_key()函数

2.run_program()函数

 

  • 8
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 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)时间片轮转调度 (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.实验目的 加深对进程概念的理解,明确进程和程序的区别; 深入了解系统如何组织进程、创建进程; 进一步认识如何实现处理器调度。 2.实验预备知识 进程的概念; 进程的组织方式; 进程的创建; 进程的调度。 3.实验内容 编写程序完成单处理机系统中的进程调度,要求采用时间片轮转调度算法。实验具体包括:首先确定进程控制块的内容,进程控制块的组成方式;然后完成进程创建原语和进程调度原语;最后编写主函数对所作工作进程测试。 4.提示与讲解 这个实验主要要考虑三个问题:如何组织进程、如何创建进程和如何实现处理器调度。 考虑如何组织进程,首先就要设定进程控制块的内容。进程控制块PCB记录各个进程执行时的情况。不同的操作系统,进程控制块记录的信息内容不一样。操作系统功能越强,软件也越庞大,进程控制块记录的内容也就越多。这里的实验只使用了必不可少的信息。一般操作系统中,无论进程控制块中信息量多少,信息都可以大致分为以下四类: ① 标识信息 每个进程都要有一个惟一的标识符,用来标识进程的存在和区别于其他进程。这个标识符是必不可少的,可以用符号或编号实现,它必须是操作系统分配的。在后面给出的参考程序中,采用编号方式,也就是为每个进程依次分配一个不相同的正整数。
首先,需要定义一个进程的结构体,包含进程名、进程优先数、进程状态等信息: ```c #define MAX_PROCESS_NUM 100 // 最大进程数 #define PROCESS_NAME_LEN 20 // 进程名长度 typedef struct { int pid; // 进程ID char name[PROCESS_NAME_LEN]; // 进程名 int priority; // 进程优先数 int state; // 进程状态,0表示就绪,1表示运行,2表示阻塞 } PCB; PCB process_list[MAX_PROCESS_NUM]; // 进程列表 int process_num = 0; // 当前进程数 ``` 接下来,可以实现一个按优先数调度的函数,该函数按照进程的优先数从高到低排序,然后选择优先数最高的进程执行: ```c void schedule() { int i, j; PCB tmp; // 按优先数从高到低排序 for (i = 0; i < process_num - 1; i++) { for (j = i + 1; j < process_num; j++) { if (process_list[i].priority < process_list[j].priority) { tmp = process_list[i]; process_list[i] = process_list[j]; process_list[j] = tmp; } } } // 选择优先数最高的进程执行 int running_pid = process_list[0].pid; process_list[0].state = 1; // 执行该进程 // ... } ``` 当一个进程创建时,需要为其分配一个唯一的进程ID,可以使用一个全局变量pid_counter来记录已经分配的最大ID,每次创建新进程时,将pid_counter加1并赋值给新进程的pid: ```c int pid_counter = 0; // 进程ID计数器 int create_process(char* name, int priority) { if (process_num >= MAX_PROCESS_NUM) { printf("Error: too many processes!\n"); return -1; } PCB new_process; new_process.pid = ++pid_counter; strcpy(new_process.name, name); new_process.priority = priority; new_process.state = 0; // 初始状态为就绪 process_list[process_num++] = new_process; // 加入进程列表 return new_process.pid; } ``` 以上是一个简单的按优先数调度算法实现处理器调度的示例。在实际应用中,还需要考虑更多的情况,例如进程的阻塞和唤醒,进程的时间片轮转等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值