操作系统Nachos实验

    xiaoxiao2021-12-14  19

    Nachos的时间定时器Alarm的解读

    首先想要提一句的是在本文最后提供了全部个人的实验报告,里面有对其他实验的一些本人的见解,也有一些源码,写得不好,大家见谅。 关于如何在eclipse中部署这个操作系统,和平常的程序导入一样,但是要注意,把内部的project这个文件夹下的不同的配置文件拷到项目目录最外层才能进行相应的实验。 闲话少说,先认识一下操作系统:这个系统分Java和c语言两个版本,按照我的看法,java的更容易去理解,同时系统较小,也实现了硬件模拟功能,但是也有缺点: 1)它的内核不是保存在模拟器的RAM中,这样,它不会受到内存容量的限制。这意味着内核数据结构的大小不是影响系统性能的重要因素,使得数据结构大小和空间容量的 权衡不用考虑,这在一个实际操作系统设计中是不现实的。 2)其次,NACHOS是与底层硬件相隔离的,所有机器模拟器和被模拟的硬件之间的接口由C++对象设计。这意味着学生不需要了解要访问的真正硬件是如何工作,而这些技 术对于编写核心程序的程序员来说是很重要的。 3)再有就是NACHOS这种特殊结构很难移植到实际硬件机器上直接执行。 说了这么多开始进入正题。

    题目

    通过修改Alarm类的waitUntil (long x)方法实现。一个线程通过调用waitUntil (long x)方法将自己挂起,一直到经过x时间再被唤醒。 这对现实操作很有用,例如,光标的周期闪 烁。线程经过x时间后唤醒,但不需要立刻运行,而是加入 readyqueue中。 不建立任何多余的线程实现waitUntil (),只需要修改waitUntil()中断处理程序和计时器。waitUntil()不受 限于任何一个线程,任何线程可以调用它实现被挂起。 对于这个的题目,我们首先要了解的是Nachos中的计时器:

    Nachos中断处理时机;所以,在Nachos中只有在时钟前进时,才会检查;在有些中断处理程序的最后可能要进行正文切换;在这个中断系统基础上,Nachos模拟了各种硬件;

    Timer类模拟定时器;

    Timer类模拟定时器。定时器每隔X个时钟周期就向CPU发一个时钟中断。它是时间片管理必不可少的硬件基础。它的实现方法是将一个即将发生的时钟中断放入中断队列,

    到了时钟中断应发生的时候,中断系统将处理这个中断,在中断处理的过程中又将下一个即将发生的时钟中断放入中断队列,这样每隔X个时钟周期,就有一个时钟中断发生。

    由于Nachos是一个软件模拟的系统,有很多的随机事件需要通过一定的控制来实现。所以系统中在计算下一个时钟中断应发生的时间时,还加入了一些随机值,使得中断发

    的时间间隔不确定,这样就与现实的定时器更相似。

    这样我们就可以知道,Nachos内部有自己的始终定时器,而且还有一个随机制度,导致可能会出现实际与计算值的偏差。

    在了解了内部的时钟中断方式之后,我们再来看这个题目,分析一下:

    实现这种通过时间控制线程沉睡的方式主要是增加相应的参数。通过时钟进行判断。在等待队列中,每个除了可以被wake()唤醒之外,还能够根据自己所存储的时间来进

    行判断是不是该苏醒加入就绪队列等待执行。这个判断可以每隔一定的时间就循环遍历等待队列来做出。定时器中断处理程序被称为机器计时器定期(大约每500时钟周期)。当

    前线程产生后,如果有另一个必须运行的线程,则强制上下文切换。

    当前线程睡眠至少x时间周期,在定时器中断处理程序中将其唤醒。当现在时间(current time) >= (WaitUntil called time)+(x)时,线程必须被唤醒(在调度准备集)在

    一个定时器中断的产生时。

    这样我们可以订立初步的方案:

    在创建线程的时候将时间进行保存,然后将时间和线程存到一起,放入等待队列,然后每隔一定的时钟中断检查一次等待队列是不是有时间满足的,如果有,就放到就绪队

    列等待执行。这样就实现了整个实验的情况

    主要修改的是Alarm类,其中首先是要利用nachos系统中每隔一定时间就会回调执行的函数体:Alarm.timerInterrupt();这个方法会每隔一定的时间调用一次。这样,我们将

    判断等待队列中线程等待时间的函数方法写在里面,就可以在每隔一段时间遍历后,将超过等待时间的线程从等待队列中取出来放置到就绪队列中。 waitUntil()方法使用了一个队列可以存放线程以及唤醒时间,这样在线程初始化的时候能够将相应的唤醒时间一起加入到这个等待队列中,等到可以唤醒的时间,再进行调用

    wake()方法将能够唤醒的线程加入就绪队列。 Waiter()内部类定义了一个数据结构,该数据结构就是用来存放Kthread类的线程和这个线程等待时间的。

    这样我们就能够完成这个实验了:

    package nachos.threads; import java.util.LinkedList; import java.util.ListIterator; import nachos.machine.*; public class Alarm { public Alarm() { Machine.timer().setInterruptHandler(new Runnable() { public void run() { timerInterrupt(); } }); } public void timerInterrupt() {// 产生时间中断,将时间符合的线程放入ready队列以便执行 boolean status = Machine.interrupt().disable(); long currenttime = Machine.timer().getTime(); int size = linkedlist.size(); if (size == 0) ; else for (int i = 0; i < size; i++) { if (currenttime < linkedlist.get(i).getWakeTime()) ; else { KThread thread = linkedlist.get(i).getThread(); thread.ready(); linkedlist.remove(i); size--; i = 0; currenttime = Machine.timer().getTime(); } } KThread.currentThread().yield(); Machine.interrupt().restore(status); } public void waitUntil(long x) {// 将线程与时间结合放入一个有序链表,线程休眠 boolean status = Machine.interrupt().disable(); long waketime = Machine.timer().getTime() + x; KThreadWakeTime kthreadwaketime = new KThreadWakeTime( KThread.currentThread(), waketime); int size = linkedlist.size(); if (size == 0) linkedlist.add(kthreadwaketime); else for (int i = 0; i < size; i++) { if (waketime < linkedlist.get(i).getWakeTime()) { linkedlist.add(i, kthreadwaketime); break; } if (i == size - 1 && waketime >= linkedlist.get(i).getWakeTime()) linkedlist.add(i + 1, kthreadwaketime); } KThread.currentThread().sleep(); Machine.interrupt().restore(status); } public class KThreadWakeTime { private KThread thread = null; private long waketime = 0; public KThreadWakeTime(KThread thread, long waketime) { this.thread = thread; this.waketime = waketime; } public KThread getThread() { return thread; } public long getWakeTime() { return waketime; } } LinkedList<KThreadWakeTime> linkedlist = new LinkedList(); }

    这是对Alarm的修改,大家可以自行了解参照。

    接下来就讨论一下重点内容,并不是通常遇到的计算好的唤醒时间和实际唤醒时间不一样的情况。大家要注意,这里面的时间单位是Nachos自己定义的,所以具体与现实时间怎么对比

    2000约1秒

    转载请注明原文地址: https://ju.6miu.com/read-965465.html

    最新回复(0)