C++编程实现模拟中断处理
实验一 中断处理
实验题目
计算机系统工作过程中,若出现中断事件,硬件就把它记录在中断寄存器中。中断寄存器的每一位可与一个中断事件对应,当出现某中断事件后,对应的中断寄存器的某一位就被置成“1”。
处理器每执行一条指令后,必须查中断寄存器,当中断寄存器内容不为“0”时,说明有中断事件发生。硬件把中断寄存器内容以及现行程序的断点存在主存的固定单元。操作系统分析保存在主存固定单元中的中断寄存器内容就可知道出现的中断事件的性质,从而作出相应的处理。
本实验中,用从键盘读入信息来模拟中断寄存器的作用,用计数器加1来模拟处理器执行了一条指令。每模拟一条指令执行后,从键盘读入信息且分析,当读入信息=0时,表示无中断事件发生,继续执行指令;当读入信息=1时,表示发生了时钟中断事件,转时钟中断处理程序。
假定计算机系统有一时钟,它按电源频率(50Hz)产生中断请求信号,即每隔20毫秒产生一次中断请求信号,称时钟中断信号,时钟中断的间隔时间(20毫秒)称时钟单位。
学生可按自己确定的频率在键盘上键入“0”或“1”来模拟按电源频率产生的时钟中断信号。
中断处理程序应首先保护被中断的现行进程的现场(通用寄存器内容、断点等),现场信息可保存在进程控制块中;然后处理出现的中断事件,根据处理结果修改被中断进程的状态;最后转向处理器调度,由处理器调度选择可运行的进程,恢复现场使其运行。
本实验主要模拟中断事件的处理,为简单起见可省去保护现场和处理器调度的工作。
为模拟时钟中断的处理,先分析一下时钟中断的作用。利用时钟中断可计算日历时钟,也可作定时闹钟等。
计算日历时钟——把开机时的时间存放在指定的称为“日历时钟”的工作单元中,用一计时器累计时钟中断次数。根据时钟中断的次数和时钟单位(20毫秒)以及开机时的日历时钟可计算出当前的精确的日历时钟。
定时闹钟——对需要定时的场合,可把轮到运行的进程的时间片值送到称为“定时闹钟”的工作单元中,每产生一次时钟中断就把定时闹钟值减1,当该值为“0”时,表示确定的时间已到,起到定时的作用。
本实验的模拟程序可由两部分组成,一部分是模拟硬件产生时钟中断,另一部分模拟操作系统的时钟中断处理程序。模拟程序的算法如图。其中,保护现场和处理器调度的工作在编程序时可省去。约定处理器调度总是选择被中断进程继续执行。
程序中使用的数据结构及符号说明
字符数组(数据结构:数组)
char *s_st;
:开机时间的字符串形式。
char *s_now;
:当前时间的字符串形式。
time_t(长整型):
time_t st;
:开机时间自 1970 年 1 月 1 日以来经过的秒数。
time_t now;
: 当前时间自 1970 年 1 月 1 日以来经过的秒数。
整型(int):
int count;
:(指令)计数器。
int timer;
:(时间中断)计时器。
int wr;
:键盘输入信息。
int time_alarm
:定时闹钟(时钟单位为20毫秒)。
int p;
:距离开机时间经过的时间(单位:毫秒)。
源程序及注释:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <iostream> #include <ctime> using namespace std;int main () { time_t st = time (0 ); char *s_st = ctime (&st); cout << "开机时间为:" << s_st; int count = 0 ; int timer = 0 ; int wr; int time_alarm; cout << "请输入定时闹钟:" ; cin >> time_alarm; while (time_alarm != 0 ) { cout << "执行了一条指令" << endl; count++; cout << "请输入模拟的时钟中断信号:" ; cin >> wr; if (wr == 1 ) { cout << "时钟中断,保存现场" << endl; timer++; time_alarm--; cout << "处理器调度" << endl; } } int p; p = timer * 20 ; time_t now = st + p / 1000 ; char *s_now = ctime (&now); cout << s_now; return 0 ; }
程序运行时的初值和运行结果
初值:
结果:
经过了50个定时闹钟,即1秒。
思考题:
将进程调度策略结合到本实验中,可选用时间片轮转的调度策略。给每个进程分配一个相同的时间片,每产生一次时钟中断经处理后,被中断进程时间片减1,时间片值!=0时,该进程优先运行,若时间片值=0且该进程尚未运行结束,则将它排入队尾,再给它分配一个时间片,直到所有的进程运行结束。应怎样设计进程控制块?各进程的状态怎样变化?在本实验的程序中加入处理器调度程序。
源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stdlib.h> #include <iomanip> using namespace std;#define N 1000000 int n, q, temp_q; struct process { int id; int pos; int arrive; int work; int begin; int end; int turnaround; int wait; bool in; bool finish; int rest; } proc[N]; queue <process> ready; bool cmp_FCFS (process a, process b) { if (a.arrive != b.arrive) return a.arrive < b.arrive; else return a.id < b.id; }void init () { cout << "请输入进程个数:" ; cin >> n; cout << "请输入时间片大小:" ; cin >> q; temp_q = q; cout << "请按进程到达先后输入进程信息(1~n):到达时间 区间时间" << endl; for (int i = 1 ; i <= n; i++) { cout << "进程" << i << ":" ; cin >> proc[i].arrive >> proc[i].work; proc[i].id = i; proc[i].in = 0 ; proc[i].begin = -1 ; proc[i].finish = 0 ; proc[i].rest = proc[i].work; } sort (proc, proc + n + 1 , cmp_FCFS); for (int i = 1 ; i <= n; i++) { proc[i].pos = i; } }bool cmp_id (process a, process b) { return a.id < b.id; }void RR_one (int timer) { for (int i = 1 ; i <= n; i++) { if (!proc[i].in && proc[i].arrive == timer) { proc[i].in = 1 ; ready.push (proc[i]); } } if (!ready.empty ()) { process t = ready.front (); ready.pop (); if (t.begin == -1 ) { t.begin = timer; } temp_q--; t.rest--; cout << "进程" << t.id << "正在运行..." ; if (t.rest == 0 ) { cout << "该进程已完成" ; t.end = timer + 1 ; t.finish = 1 ; t.turnaround = t.end - t.arrive; t.wait = t.turnaround - t.work; proc[t.pos] = t; } if (temp_q == 0 ) { if (t.rest > 0 ) { ready.push (t); } temp_q = q; } cout << endl; } }void display () { sort (proc, proc + n + 1 , cmp_id); cout << "所有进程当前状态如下:" << endl; cout << setw (8 ) << "进程编号" << setw (10 ) << "到达时间" << setw (10 ) << "区间时间" << setw (10 ) << "开始时间" << setw ( 10 ) << "完成时间" << setw (10 ) << "周转时间" << setw (10 ) << "等待时间" ; cout << endl; for (int i = 1 ; i <= n; i++) { cout << left << setw (10 ) << proc[i].id << setw (10 ) << proc[i].arrive << setw (10 ) << proc[i].work; if (proc[i].begin != -1 ) cout << left << setw (10 ) << proc[i].begin; else cout << left << setw (10 ) << "未开始" ; if (proc[i].finish) cout << left << setw (10 ) << proc[i].end << setw (10 ) << proc[i].turnaround << setw (10 ) << proc[i].wait; else cout << left << setw (10 ) << "未完成" << setw (10 ) << "未完成" << setw (10 ) << "未完成" ; cout << endl; } return ; }int main () { init (); time_t st = time (0 ); char *s_st = ctime (&st); cout << "开机时间为:" << s_st; int count = 0 ; int timer = 0 ; int wr; int time_alarm; cout << "请输入定时闹钟:" ; cin >> time_alarm; while (time_alarm != 0 ) { cout << "执行了一条指令..." << endl; count++; cout << "请输入模拟的时钟中断信号:" ; cin >> wr; if (wr == 1 ) { cout << "时钟中断,保存现场..." << endl; RR_one (timer); timer++; time_alarm--; } } int p; p = timer * 20 ; time_t now = st + p / 1000 ; char *s_now = ctime (&now); cout << "当前时间为:" << s_now; display (); return 0 ; }
程序运行时的初值和运行结果
初值
运行结果
实验心得
本次实验让我通过编写模拟程序,进一步了解中断及中断处理程序的作用。在编程过程中,我接触到了C++中<ctime>
这个时间相关库,学会通过time_t st = time(0)
得到基于当前系统的开机时间(自 1970 年 1 月 1 日以来经过的秒数),再使用ctime(&st)
将该时间转化为字符串形式(格式为:Www Mmm dd hh:mm:ss yyyy
)。而对于中断的模拟是基于定时时钟的while
循环。此外,我进行了拓展。一是,通过信息输入,再对时间的tm结构的处理,可以自己设定开机时间(见源程序末尾的注释)。二是完成了思考题,将处理器调度和时间中断相结合,刚好地了解中断的运行机制,并有效提高了编程能力。
本博客所有文章除特别声明外,均为博客作者本人编写整理,转载请联系作者!