要求:
需要完成Alarm类,实现waitUntil(longx )方法。一个 线程调用waitUntil将挂起自己的执行,直到时间变为now+x。线程在唤醒后将它们放入到等待队列中。不生成其他的线程实现waitUntil方 法,修 改waitUntil方 法 和定 时 器 中 断 处 理 程 序 。waitUntil不限于一个线程,任何数目的线程均可调用它,每次一个线程挂起。现在的代码只是让程序能运行,并没有真正实现该功能。挂起该进程,就必须挂起到一个地方,能够根据时间再次唤醒该进程。在这里用信号量的方式来实现唤醒功能(当然也可以用条件变量)。Alarm构 造 函数 调 用setInterruptHandler(Runnablehandler)把timerInterrupt()方法注册为时钟回调方法,即时钟每次tick时调用。初始化一张线程等待表,线程等待表存放一种数据结构,该数据结构包含正在等待的线程的ID及需要被唤醒的时间以及信号量。Alarm要求实现waitUntil(longx)方法,该方法用于等待一定的时间将线程唤醒,等待时间长度为x,Nachos的时间采用模拟的tick计数,所以实现时应使用Machine.timer().getTime()方法获取当前时间加上等待的时间长度表示线程被唤起的时间点,加入到线程等待表中,并调KThread.sleep()挂起当前线程。timerInterrupt()方法检查线程等待表,将其中超时的线程唤醒,这里可以用优先队列存储表,优先队列将按超时时间排序,检查时便不需要遍历整张表,提高效率。
具体实现如下:
先构建一个数据结构,该数据结构包含一个线程,被唤醒的时间,信号量(写在alarm.java)
// 该结构是由一个当前线程,等待的时间,相应的条件变量组成;
private class WaitItem {
KThread thread;
long waittime;
// Condition2 condition;
Semaphore semaphore;
public WaitItem(KThread thread, long waittime, Semaphore semaphore) {
this.thread = thread;
this.waittime = waittime;
this.semaphore = semaphore;
}
}
初始化一个等待队列来存放这些该结构,在这里我们用
<span style="white-space:pre"> </span>// 等在alarm上的线程
public static LinkedList<WaitItem> alarmqueue = new LinkedList<WaitItem>();
当一个线程等待的时候,则将该线程放入等待队列中睡眠,则 waituntil函数如下:
public void waitUntil(long x) {
// for now, cheat just to get something working (busy waiting is bad)
long wakeTime = Machine.timer().getTime() + x;
Semaphore semaphore = new Semaphore(0);
WaitItem waitItem = new WaitItem(KThread.currentThread(), wakeTime,
semaphore);
alarmqueue.add(waitItem);
semaphore.P();
}
Alarm构 造 函数 调 用 setInterruptHandler(Runnablehandler)把 timerInterrupt()方法注册为时钟回调方法 ,即时钟每次 tick时调用。我们利用时钟回调来检查该线程是都到达被唤醒的时间,即没 500个 ticks检查一次,如果没有到,则继续 sleep,如果时间到了或者是超过了则唤醒。故
timerInterrupt()函数实现如下:
public void timerInterrupt() {
for (Iterator x = alarmqueue.iterator(); x.hasNext();) {
WaitItem item = (WaitItem) x.next();
// System.out.println(item.toString());
if (item.waittime <= Machine.timer().getTime()) {
item.semaphore.V();
x.remove();
}
}
}
这里重新写了他的测试方式,(测试方法写在KThread.java),并且ping线程在循环中使用Alarm进行延迟,同时测试了Alarm的waitUntil方法。然后在ThreadedKernel 里调用KThread.AlarmTest(); 进行测试
private static class AlarmPingTest implements Runnable {
AlarmPingTest(SynchList ping, SynchList pong) {
this.ping = ping;
this.pong = pong;
}
public void run() {
for (int i=0; i<10; i++) {
System.out.println("ping remove " +i);
Object o = ping.removeFirst();
System.out.println("ping remove done " + o);
System.out.println("pong add " + i);
pong.add(o);
System.out.println("pong add done "+ i);}
}
private SynchList ping;
private SynchList pong;
}
/**
* Alarm_waituntil 测试
* @author dan
*
*/
public static void AlarmTest() {
SynchList ping = new SynchList();
SynchList pong = new SynchList();
new KThread(new AlarmPingTest(ping, pong)).setName("alarmtest").fork();
for (int i = 0; i < 5; i++) {
Integer o = new Integer(i);
System.out.println("ping add " + i);
ping.add(o);
ping.add(o);
System.out.println("ping add done " + i);
// 使用 Alarm 的 waitUntil 方法延迟
new Alarm().waitUntil(10000000);
System.out.println("alarmtest wake");
System.out.println("pong remove " + i);
// Lib.assertTrue(pong.removeFirst() == o);
pong.removeFirst();
pong.removeFirst();
System.out.println("pong remove done " + i);
}
}
对应输出:pingadd 0
pingadd done 0
pingremove 0
pingremove done 0
pongadd 0
pongadd done 0
pingremove 1
pingremove done 1
pongadd 1
pongadd done 1
pingremove 2
thread0wake
pongremove 0
pongremove done 0
pingadd 1
pingadd done 1
pingremove done 2
pongadd 2
pongadd done 2
pingremove 3
pingremove done 3
pongadd 3
pongadd done 3
pingremove 4
thread0wake
pongremove 1
pongremove done 1
pingadd 2
pingadd done 2
pingremove done 4
pongadd 4
pongadd done 4
pingremove 5
pingremove done 5
pongadd 5pong add done 5
pingremove 6
thread0wake
pongremove 2
pongremove done 2
pingadd 3
pingadd done 3
pingremove done 6
pongadd 6
pongadd done 6
pingremove 7
pingremove done 7
pongadd 7
pongadd done 7
pingremove 8
thread0wake
pongremove 3
pongremove done 3
pingadd 4
pingadd done 4
pingremove done 8
pongadd 8
pongadd done 8
pingremove 9
pingremove done 9
pongadd 9
pongadd done 9
thread0wake
pongremove 4
pongremove done 4