到关于该线程的信息(线程: 当前线程, 唤醒时间: 当前时间+x), 该线程设定唤醒时间并阻塞,并调用sleep操作使当前线程挂起, 放入队列中。在时钟回调函数中(大约每500个时钟间隔调用一次) 有一次中断,中断时则依次检查队列中的每个对象,将队列中此时应当唤醒的进程加入就绪队列。如果唤醒时间大于当前时间, 则将该对象移出队列并执行wake操作将相应线程唤醒。
(3)Waiter()是一个用来管理和存储多个Kthread及其唤醒时间的内部类,属性分别为该Kthread与其唤醒时刻waketime。
2.3.3关键点与难点
线程调用waitUntil方法之后会终止,该线程设定唤醒时间并阻塞,直到传入的时间之后才可以执行。线程只是放入就绪队列,等待分配。可以使用一个线程队列,但是不能产生额外的线程。
Timer每过500个clock ticks会产生一个timeInterrupt。timeInterupt时,会运行handle()线程,将handler线程功能设置为将队列中此时应当唤醒的进程加入就绪队列。
2.3.4实现代码
class Waiter {
private LinkedList
9
Waiter(long wakeTime, Kthread thread) { }
private long wakeTime; // 唤醒时间
this.wakeTime = wakeTime; this.thread = thread;
private Kthread thread; // 等待的线程 }
public void waitUntil(long x) {
}
// 系统关中断
oolean intStatus = Machine.interrupt().disable();
// for now, cheat just to get something working (busy waiting is // 确定唤醒的时间
long wakeTime = Machine.timer().getTime() + x;
Waiter waiter = new Waiter(wakeTime, Kthread.currentThread()); // 将线程加入到等待队列上 waitlist.add(waiter);
System.out.println(“线程:” + Kthread.currentThread().getName()
+ “\\t休眠时间:” + Machine.timer().getTime() + “\\t下次唤醒+ wakeTime);// 当前线程设定唤醒时间并阻塞,挂起
bad)
时间:”
Kthread.sleep();// 开中断
Machine.interrupt().restore(intStatus);
2.4 Task 1.4条件变量实现同步消息 2.4.1题目要求
使用条件变量来实现一个字长信息的发送和接收同步。使用void speak(int word) 和int listen()函数来实现通讯(Communicator)类的通讯操作。Speak函数具有原子性,在相同地Communicator类中等待listen函数被调用,然后将此字发生给listen函数。一旦传送完毕,两个函数都返回(listen函数返回此字)。
2.4.2题目分析与实现方案
解决方案要满足使用同一个通讯对象实例中多个speaker和listener能够相互通讯。(注意:这种情况等于0字长的缓冲区;既然缓冲区没用空间,那么需要生产者和消费者直接进行交互,要求他们相互等待)。每一个通讯实例只能使用一个lock类,如果使用多于一个lock类,会将事情复杂化。
10
每个Communicator拥有的锁(保证操作的原子性) 和与该锁联系的两个条件变量用于保证speaker和listener间的同步。在speak函数中, 首先检查是否已经有speaker在等待(speaknum>0) 或无listener等待,满足这两种情况就挂起。 若不满足,则设置变量, 准备数据并唤醒一个listener。
在listen函数中, 增加一个listener后, 首先, 然后这个问题其实是一个缓冲区长度为0的生产者/消费者问题。
Speak():先获得锁,然后进行判断,如果没有听者等待,就要把说者放入队列然后睡眠。如果有听者等待,就要唤醒一个听者,然后传递消息,最后释放锁。
Listen():先获得锁,然后进行判断尝试唤醒speaker,如果没有说者等待,就要把听者放入队列然后睡眠。如果有说者等待,就要唤醒一个说者,将自己挂起以等待speaker准备好数据再将自己唤醒,然后传递消息,最后释放锁。
2.4.3关键点与难点
当有多个speaker和listener时,它们也只能是一对一的, 即一个speaker只能将数据发送到一个listener, 一个listener也只能接收来自一个speaker的数据, 其余的speakers和listeners都需要等待。多个speaker阻塞时需要保存每一个speaker的word,阻塞的speaker挂在Condition对象的Queue队列上。因为无缓冲区,listener唤醒说者后要先挂起,消息在speaker准备好后才传递。
2.4.4实现代码
11
public class Communicator {
private Lock lock; // 互斥锁 private int word = 0;
private static int speakercount = 0; // 说者数量 private static int listenercount = 0; // 听者数量
LinkedList
lock = new Lock();
speaker = new Condition2(lock); listener = new Condition2(lock);
者话语的队列
/*先获得锁,然后进行判断,如果没有听者等待,就要把说者放入队列然后睡眠。 如果有听者等待,就要唤醒一个听者,然后传递消息,最后释放锁*/
public void speak(int word) {// 系统关中断 oolean intStatus = Machine.interrupt().disable();
// 拿到锁
lock.acquire();// 没有听者,说者睡眠,队列存储说者的话 if (listenercount == 0) {
speakercount++;
Wordqueue.offer(word);
speaker.sleep();// 尝试唤醒听者 listener.wake();// 说者队列人数减一 speakercount--;
} else {// 准备消息,唤醒听者 Wordqueue.offer(word);
listener.wake(); }// 释放锁
lock.release();// 系统开中断
Machine.interrupt().restore(intStatus);
System.out.println(Kthread.currentThread().getName() + “ 发出信
息 “ + word); return;
}
oolean intStatus = Machine.interrupt().disable();// 获得锁 lock.acquire();
if (speakercount != 0) {
speaker.wake();
12
public int listen() {// 系统关中断
相关推荐: