操作系统实验三-中断处理

操作系统第三次实验中断处理

个人博客地址

中断处理

一、实验内容

  • 运用某种高级语言(如C或C++)模拟时钟中断的产生及设计一个对时钟中断事件进行处理的模拟程序。

二、实验目的

  • 现代计算机系统的硬件部分都设有中断机构,中断机构能发现中断事件,且当发现中断事件后迫使正在处理器上执行的进程暂时停止执行,而让操作系统的中断处理程序占有处理器去处理出现的中断事件。
  • 本实验模拟“时钟中断事件”的处理,对其它中断事件的模拟处理,可根据各中断事件的性质确定处理原则,制定算法,自行设计。
  • 通过本实验了解中断及中断处理程序的作用。

三、实验题目

  1. 计算机系统工作过程中,若出现中断事件,硬件就把它记录在中断寄存器中。中断寄存器的每一位可与一个中断事件对应,当出现某中断事件后,对应的中断寄存器的某一位就被置成“1”。
  • 处理器每执行一条指令后,必须查中断寄存器,当中断寄存器内容不为“0”时,说明有中断事件发生。硬件把中断寄存器内容以及现行程序的断点存在主存的固定单元。操作系统分析保存在主存固定单元中的中断寄存器内容就可知道出现的中断事件的性质,从而作出相应的处理。
  • 本实验中,用从键盘读入信息来模拟中断寄存器的作用,用计数器加1来模拟处理器执行了一条指令。每模拟一条指令执行后,从键盘读入信息且分析,当读入信息=0时,表示无中断事件发生,继续执行指令;当读入信息=1时,表示发生了时钟中断事件,转时钟中断处理程序。
  1. 假定计算机系统有一时钟,它按电源频率(50Hz)产生中断请求信号,即每隔20毫秒产生一次中断请求信号,称时钟中断信号,时钟中断的间隔时间(20毫秒)称时钟单位。
  • 按自己确定的频率在键盘上键入“0”或“1”来模拟按电源频率产生的时钟中断信号。
  1. 中断处理程序应首先保护被中断的现行进程的现场(通用寄存器内容、断点等),现场信息可保存在进程控制块中;然后处理出现的中断事件,根据处理结果修改被中断进程的状态;最后转向处理器调度,由处理器调度选择可运行的进程,恢复现场使其运行。
  • 本实验主要模拟中断事件的处理,为简单起见可省去保护现场和处理器调度的工作。
  1. 为模拟时钟中断的处理,先分析一下时钟中断的作用。利用时钟中断可计算日历时钟,也可作定时闹钟等。
  • 计算日历时钟——把开机时的时间存放在指定的称为“日历时钟”的工作单元中,用一计时器累计时钟中断次数。根据时钟中断的次数和时钟单位(20毫秒)以及开机时的日历时钟可计算出当前的精确的日历时钟。
  • 定时闹钟——对需要定时的场合,可把轮到运行的进程的时间片值送到称为“定时闹钟”的工作单元中,每产生一次时钟中断就把定时闹钟值减1,当该值为“0”时,表示确定的时间已到,起到定时的作用。
  1. 本实验的模拟程序可由两部分组成,一部分是模拟硬件产生时钟中断,另一部分模拟操作系统的时钟中断处理程序。模拟程序的算法如图1-1。其中,保护现场和处理器调度的工作在编程序时可省去。约定处理器调度总是选择
    被中断进程继续执行。

  2. 按模拟算法设计程序,要求显示或打印开机时间、定时闹钟初值、定时闹钟为“0”时的日历时钟。确定三个不同的定时闹钟初值,运行设计的程序,观察得到的结果。

image-20211112104249163

思考题

将进程调度策略结合到本实验中,可选用时间片轮转的调度策略。给每个进程分配一个相同的时间片,每产生一次时钟中断经处理后,被中断进程时间片减1,时间片值¹0时,该进程优先运行,若时间片值=0且该进程尚未运行结束,则将它排入队尾,再给它分配一个时间片,直到所有的进程运行结束。应怎样设计进程控制块?各进程的状态怎样变化?在本实验的程序中加入处理器调度程序

四、实验设计与过程

1. 时钟中断事件模拟程序

数据结构和符号说明

因为该实验中断结束后继续调用上一个进程,直到进程结束,所以未设计进程结构体;

符号说明:

	time_t t;//存储日历时间类型
	struct tm *cc;//用来保存时间和日期的结构
	
	int timer = 0;	 //计时器
	int counter = 0; //计数器
	int clock_alarm; //定时时钟
	int ir = 0;		 //中断寄存器
源代码

该程序思路很清晰,设置一个定时时钟,然后进行中断判断,当输入为1时,中断进程,定时闹钟减一,输入为0时,继续执行进程。

当时钟为0时,程序结束,计算时间后输出当前时间。

#include <bits/stdc++.h>
using namespace std;
int main()
{
	time_t t;//存储日历时间类型
	struct tm *cc;//用来保存时间和日期的结构
	
	int timer = 0;	 //计时器
	int counter = 0; //计数器
	int clock_alarm; //定时时钟
	int ir = 0;		 //中断寄存器

	time(&t); //获取系统时间
	cc = localtime(&t);//将time值分解为tm结构

	cout << "开机时间:" << asctime(cc);//以字符串形式输出时间
	cout << "定时闹钟的设定值为:";
	cin >> clock_alarm;
	cout << endl;

	while (clock_alarm != 0) //当未到定时时钟设定值时
	{
		if (ir != 0)
			cout << "正在进行处理器调度···" << endl;
		cout << "一条指令正在执行" << endl;
		counter++;
		cout << "是否有中断产生,1是,0否:"; //每输入一次频率设置为1s
		cin >> ir;
		if (ir == 0)
		{
			cout << "无中断,指令继续执行" << endl;
		}
		else
		{
			cout << "正在保护现场···" << endl //保护现场具体过程省略
				 << "现场保护完成" << endl;
			cout << "---------------------------------------" << endl;
			timer++;	   //计时器加1
			clock_alarm--; //定时闹钟减1
		}
	}
	cout << "时间过去了" << timer << "s" << endl;
	cout << "现在时间是:" << endl;
	cc->tm_hour += timer / 3600; //计算当前时间
	timer %= 3600;
	cc->tm_min += timer / 60;
	timer %= 60;
	cc->tm_sec += timer;
	cout << asctime(cc);
	return 0;
}
程序初值和运行结果

定时闹钟clock_alarm=5

image-20211112110700237

定时闹钟clock_alarm=3

image-20211112110831917

定时闹钟clock_alarm=6

image-20211112111022197

2. 思考题:时钟中断程序加调度

数据结构
struct PCB //进程结构体
{
	int time_slice;	 //时间片
	int time_remain; //进程剩余运行时间
	int id;			 //进程id
};
符号说明
queue<PCB> p; //进程的就绪队列
PCB process;//当前进程
time_t t;//存储日历时间类型
struct tm *cc;//用来保存时间和日期的结构
函数说明
时间计算函数
void time_caculate(int timer) //计算当前时间
{
	cout << "现在时间是:" << endl;
	cc->tm_hour += timer / 3600;
	timer %= 3600;
	cc->tm_min += timer / 60;
	timer %= 60;
	cc->tm_sec += timer;
	cout << asctime(cc);
}
进程初始化函数
void process_init(queue<PCB> &p) //进程初始化,给定一些进程的初值
{
	PCB ex[4];
	for (int i = 0; i < 4; i++)
	{
		ex[i].id = i + 1;
		ex[i].time_slice = 2;
		ex[i].time_remain = 2 + i;
		p.push(ex[i]);
	}
}
进程保存函数

保存进程的时间片信息,具体其他信息的保存省略

void process_save() //中断发生时的进程保存
{
	cout << "正在保护现场···" << endl;
	process.time_remain--; //每产生一次时钟中断经处理后,被中断进程时间减1
	process.time_slice--;  //时间片也减1

	cout << "现场保护完成" << endl;
	cout << "---------------------------------------" << endl;
}
进程调度函数

分为三种情况

第一种为进程运行时间已完成

第二种为进程时间片用完

这两种都需要切换进程

第三种则是时间片和进程剩余时间均不为零,继续运行当前进程

int process_schedule(int ir, int timer)
{

	if (process.time_remain == 0)
		ir = 1; //标记进程已结束或中断,需要切换进程
	else if (process.time_slice == 0)
	{
		ir = 1;					//当前进程已结束或中断,需要切换进程
		process.time_slice = 2; //恢复时间片
		p.push(process);		//再次放入就绪队列
	}
	else
		ir = -1; //当前进程继续运行
	if (ir == 1)
	{

		cout << "正在进行处理器调度···" << endl;
		cout << "---------------------------------------" << endl;
		process = p.front();
		if (!p.empty())
			p.pop();
		else
		{
			cout << "所以进程已经执行完成,时间过去了" << timer << "s" << endl;
			time_caculate(timer); //进程队列为空则结束,计算时间
			return 0;			  //返回0表示结束程序
		}
	}
	else if (ir == -1)
	{
		cout << "正在进行处理器调度···" << endl;
		cout << "---------------------------------------" << endl;
	}
	return 1;
}
源代码
#include <bits/stdc++.h>
using namespace std;

struct PCB //进程结构体
{
	int time_slice;	 //时间片
	int time_remain; //进程剩余运行时间
	int id;			 //进程id
};

queue<PCB> p;  //进程的就绪队列
PCB process;   //当前进程
time_t t;	   //存储日历时间类型
struct tm *cc; //用来保存时间和日期的结构

void time_caculate(int timer) //计算当前时间
{
	cout << "现在时间是:" << endl;
	cc->tm_hour += timer / 3600;
	timer %= 3600;
	cc->tm_min += timer / 60;
	timer %= 60;
	cc->tm_sec += timer;
	cout << asctime(cc);
}
void process_init(queue<PCB> &p) //进程初始化,给定一些进程的初值
{
	PCB ex[4];
	for (int i = 0; i < 4; i++)
	{
		ex[i].id = i + 1;
		ex[i].time_slice = 2;
		ex[i].time_remain = 2 + i;
		p.push(ex[i]);
	}
}
void process_save() //中断发生时的进程保存
{
	cout << "正在保护现场···" << endl;
	process.time_remain--; //每产生一次时钟中断经处理后,被中断进程时间减1
	process.time_slice--;  //时间片也减1

	cout << "现场保护完成" << endl;
	cout << "---------------------------------------" << endl;
}
int process_schedule(int ir, int timer)
{

	if (process.time_remain == 0)
		ir = 1; //标记进程已结束或中断,需要切换进程
	else if (process.time_slice == 0)
	{
		ir = 1;					//当前进程已结束或中断,需要切换进程
		process.time_slice = 2; //恢复时间片
		p.push(process);		//再次放入就绪队列
	}
	else
		ir = -1; //当前进程继续运行
	if (ir == 1)
	{

		cout << "正在进行处理器调度···" << endl;
		cout << "---------------------------------------" << endl;
		process = p.front();
		if (!p.empty())
			p.pop();
		else
		{
			cout << "所以进程已经执行完成,时间过去了" << timer << "s" << endl;
			time_caculate(timer); //进程队列为空则结束,计算时间
			return 0;			  //返回0表示结束程序
		}
	}
	else if (ir == -1)
	{
		cout << "正在进行处理器调度···" << endl;
		cout << "---------------------------------------" << endl;
	}
	return 1;
}

int main()
{

	int timer = 0;
	int counter = 0;
	int clock_alarm;
	int ir = 0; //中断寄存器

	process_init(p); //初始化进程

	time(&t);
	cc = localtime(&t);

	cout << "开机时间:" << asctime(cc);
	cout << "定时闹钟的设定值为:";
	cin >> clock_alarm;
	cout << endl;

	process = p.front();
	p.pop();
	while (clock_alarm != 0)
	{

		cout << "进程" << process.id << "正在执行" << endl;
		cout << "当前进程剩余的时间片:" << process.time_slice << endl;
		cout << "当前进程剩余执行时间:" << process.time_remain << endl;
		counter++;
		cout << "是否有中断产生,1是,0否:"; //每输入一次频率设置为1s
		cin >> ir;
		if (ir == 0)
		{
			cout << "未发生中断,进程继续执行" << endl;
			continue;
		}
		else
		{
			process_save();
			timer++;
			clock_alarm--;
			if (process_schedule(ir, timer) == 0)
				return 0;
		}
	}
	cout << "定时结束,时间过去了" << timer << "s" << endl;
	time_caculate(timer);
	return 0;
}

程序初值和运行结果

clock_alarm设定值为4

image-20211112115344801

clock_alarm设定值为5

image-20211112115544971

当所有进程运行时间小于定时闹钟设定值时:

image-20211112120044861

image-20211112120118837

五、实验总结

对于只有中断的程序设计较为简单,设置一个定时时钟,然后进行中断判断,当输入为1时,中断进程,定时闹钟减一,输入为0时,继续执行当前进程。

对于思考题,需要考虑时间片轮转调度,程序主要思路就是当进程运行时间或者时间片结束时,切换进程,否则继续执行当前进程。

这个实验相对较为容易,只考虑了就绪队列和当前运行进程。

通过这次模拟实验,我了解了中断的过程以及中断处理程序的作用,当CPU收到中断或者异常的信号时,它会暂停执行当前的程序或任务然后通过进程调度函数进行进程切换。

同时也进行了许久没写过的C++编程,代码太久没编果然会生疏,很多简单的思路总是想不清楚,但总算最后顺利完成了,还是有很多收获的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值