实验1 中断处理
一、实验内容
运用某种C++语言模拟时钟中断的产生及设计一个对时钟中断事件进行处理的模拟程序。
二、实验目的
• 现代计算机系统的硬件部分都设有中断机构,中断机构能发现中断事件,且当发现中断事件后迫使正在处理器上执行的进程暂时停止执行,而让操作系统的中断处理程序占有处理器去处理出现的中断事件。
• 本实验模拟“时钟中断事件”的处理,对其它中断事件的模拟处理,可根据各中断事件的性质确定处理原则,制定算法,自行设计。
• 通过本实验了解中断及中断处理程序的作用。
三、实验原理
1.计算机系统工作过程中,若出现中断事件,硬件就把它记录在中断寄存器中。中断寄存器的每一位可与一个中断事件对应,当出现某中断事件后,对应的中断寄存器的某一位就被置成“1”。
• 处理器每执行一条指令后,必须查中断寄存器,当中断寄存器内容不为“0”时,说明有中断事件发生。硬件把中断寄存器内容以及现行程序的断点存在主存的固定单元。操作系统分析保存在主存固定单元中的中断寄存器内容就可知道出现的中断事件的性质,从而作出相应的处理。
• 本实验中,用从键盘读入信息来模拟中断寄存器的作用,用计数器加1来模拟处理器执行了一条指令。每模拟一条指令执行后,从键盘读入信息且分析,当读入信息=0时,表示无中断事件发生,继续执行指令;当读入信息=1时,表示发生了时钟中断事件,转时钟中断处理程序。
2.假定计算机系统有一时钟,它按电源频率(50Hz)产生中断请求信号,即每隔20毫秒产生一次中断请求信号,称时钟中断信号,时钟中断的间隔时间(20毫秒)称时钟单位。
• 可按自己确定的频率在键盘上键入“0”或“1”来模拟按电源频率产生的时钟中断信号。
3.中断处理程序应首先保护被中断的现行进程的现场(通用寄存器内容、断点等),现场信息可保存在进程控制块中;然后处理出现的中断事件,根据处理结果修改被中断进程的状态;最后转向处理器调度,由处理器调度选择可运行的进程,恢复现场使其运行。
• 本实验主要模拟中断事件的处理,为简单起见可省去保护现场和处理器调度的工作。
4.为模拟时钟中断的处理,先分析一下时钟中断的作用。利用时钟中断可计算日历时钟,也可作定时闹钟等。
• 计算日历时钟——把开机时的时间存放在指定的称为“日历时钟”的工作单元中,用一计时器累计时钟中断次数。根据时钟中断的次数和时钟单位(20毫秒)以及开机时的日历时钟可计算出当前的精确的日历时钟。
• 定时闹钟——对需要定时的场合,可把轮到运行的进程的时间片值送到称为“定时闹钟”的工作单元中,每产生一次时钟中断就把定时闹钟值减1,当该值为“0”时,表示确定的时间已到,起到定时的作用。
5.本实验的模拟程序可由两部分组成,一部分是模拟硬件产生时钟中断,另一部分模拟操作系统的时钟中断处理程序。模拟程序的算法如图1-1。其中,保护现场和处理器调度的工作在编程序时可省去。约定处理器调度总是选择被中断进程继续执行。
6.按模拟算法设计程序,要求显示或打印开机时间、定时闹钟初值、定时闹钟为“0”时的日历时钟。确定三个不同的定时闹钟初值,运行设计的程序,观察得到结果。
四、实验内容
1.算法设计
【time.h中localtime结构体】
struct tm {
int tm_sec;//seconds, range 0 to 59
int tm_min;//minutes, range 0 to 59
int tm_hour;//hours, range 0 to 23
int tm_mday;//day of the month, range 1 to 31
int tm_mon;// month, range 0 to 11
int tm_year;// The number of years since 1900
int tm_wday;//day of the week, range 0 to 6
int tm_yday;//day in the year, range 0 to 365
int tm_isdst;//daylight saving time
};
【获取开机时间】
time_t rawtime; // 代表日历时间的time_t值的指针
char* t; // 日历时钟
struct tm* info;
rawtime = time(NULL);
info = localtime(&rawtime);
t = asctime(info);
【模拟时间中断】
int count = 0, count1 = 0, clock_alarm, flag = 0, Timer = 0; // 计数器,计时器,定时闹钟,判断中断条件,时间片
while (clock_alarm != 0)
{
// 模拟时间中断
do
{
cout << "一条指令已被执行!\n";
count++; // 计数器+1
cout << "主程序的计数器为:" << count - count1 << endl;
cout << "\n请输入一个数字模拟指令(0代表无中断,1代表中断):\n";
cin >> flag;
} while (flag == 0);
// 模拟中断处理
if (flag != 0)
cout << "产生中断,保护被中断的现行进程\n中断计时器为:" << count1 + 1<<endl;
count1++; // 计时器+1
clock_alarm--; // 定时闹钟-1
if (clock_alarm != 0)
cout<<"处理器调度完成!\n";
}
2.源代码
#include<iostream>
#include<time.h>
using namespace std;
int main()
{
// 初始化,显示开机时间
time_t rawtime; // 代表日历时间的time_t值的指针
int count = 0, count1 = 0, clock_alarm, flag = 0, Timer = 0; // 计数器,计时器,定时闹钟,判断中断条件,时间片
char* t; // 日历时钟
struct tm* info;
rawtime = time(NULL);
info = localtime(&rawtime);
t = asctime(info);
cout << "初始日历时间:" << t;
cout << "设置定时闹钟的值:";
cin >> clock_alarm;
cout << "设置时间片的值:";
cin >> Timer;
while (clock_alarm != 0)
{
// 模拟时间中断
do
{
cout << "一条指令已被执行!\n";
count++; // 计数器+1
cout << "主程序的计数器为:" << count - count1 << endl;
cout << "\n请输入一个数字模拟指令(0代表无中断,1代表中断):\n";
cin >> flag;
} while (flag == 0);
// 模拟中断处理
if (flag != 0)
cout << "产生中断,保护被中断的现行进程\n中断计时器为:" << count1 + 1<<endl;
count1++; // 计时器+1
clock_alarm--; // 定时闹钟-1
if (clock_alarm != 0)
cout<<"处理器调度完成!\n";
}
// 计算总的中断处理时间
double p = Timer * count1; //时间片*中断次数
int a = (int)count1 * Timer;
// 四舍五入
if ((p - a) >= 0.5) p = a + 1;
else p = a;
cout << "当前时间为:";
//中断结束后的时间=原始时间+中断次数*时间片
rawtime = rawtime + a;
// 计算运行时间
cout << ctime(&rawtime);
return 0;
}
3.实验结果
【定时闹钟值较小】
模拟中断成功。
【定时闹钟值较大】
···
模拟中断成功。
五、思考题
将进程调度策略结合到本实验中,可选用时间片轮转的调度策略。给每个进程分配一个相同的时间片,每产生一次时钟中断经处理后,被中断进程时间片减1,时间片值¹0时,该进程优先运行,若时间片值=0且该进程尚未运行结束,则将它排入队尾,再给它分配一个时间片,直到所有的进程运行结束。应怎样设计进程控制块?各进程的状态怎样变化?在本实验的程序中加入处理器调度程序。
增设时间片,修改代码如上。
六、实验总结
更加深入的了解了操作系统的中断,以及中断处理。中断,是指计算机在执行期间,系统发生了急需处理的事件,使得cpu需要马上停止当前正在执行的程序或操作,转而去处理相应的中断处理程序,待处理完后又返回处理原来被中断的位置继续执行。引发中断的事件称为中断源,中断源向cpu发出的请求中断处理信号称为中断请求,cpu收到请求去执行相应的中断处理程序称为中断响应。中断禁止:如果cpu内部的处理器状态字PSW的中断允许位被清除了,就不允许cpu响应中断,这种情况下,即使产生中断源,发出了中断请求,但cpu仍然不会响应中断。中断屏蔽:在中断请求产生后,系统有选择性的封锁一部分中断而允许一部分中断得到响应。
通过本次实验明台了中断处理的详细过程,即中断处理程序应首先保护被中断的现行进程的现场, 然后处埋出现的中新亭件,根据处理结果修改被中断程序的状态;最后转向处理器调度, 由处理器调度选择可进行的进程,恢复现场使之运行。