Task 1.2 Condition Variables
- 实验要求
- 实验关键代码
- 实验测试代码
- 关键代码分析
- 测试结果分析
实验要求
◆ Implement condition variables directly, by using interrupt enable and disable to provide atomicity
◆ We have provided a sample implementation that uses semaphores; your job is to provide an equivalent implementation without directly using semaphores (you may of course still use locks, even though they indirectly use semaphores)
◆ Once you are done, you will have two alternative implementations that provide the exact same functionality
◆ Your second implementation of condition variables must reside in class nachos.threads.Condition2
实验关键代码
变量声明
private LinkedList<KThread> waitQueue;
private Lock conditionLock;
方法实现
关键代码主要为sleep()方法,wake()方法和wakeAll()方法。
Sleep()方法:
public void sleep() {
Lib.assertTrue(conditionLock.isHeldByCurrentThread());
conditionLock.release();//释放锁
boolean preState = Machine.interrupt().disable();//关中断
waitQueue.add(KThread.currentThread());//将当前线程加入到waitQueue中
KThread.currentThread().sleep();//让当前线程睡眠
Machine.interrupt().restore(preState);//恢复中断
conditionLock.acquire();//申请锁
}
Wake()方法:
public void wake() {
Lib.assertTrue(conditionLock.isHeldByCurrentThread());
boolean preState = Machine.interrupt().disable();//关中断
if(!waitQueue.isEmpty()){//唤醒waitQueue中的一个线程
KThread a = waitQueue.removeFirst();//取出waitForQueue中一个线程
a.ready();//将取出的线程启动
}
Machine.interrupt().restore(preState);//恢复中断
}
WakeAll()方法:
public void wakeAll() {
Lib.assertTrue(conditionLock.isHeldByCurrentThread());
while(waitQueue!=null)//将waitQueue中的所有线程均唤醒
wake();
}
关键代码分析
思路分析
为什么:对于condition,原先的nachos已经给出一种方式实现,看它内部实现会发现它使用信号量实现了条件变量,但通过查看信号量底层代码,发现信号量是靠线程的睡眠和唤醒实现的,故,可以直接使用线程的睡眠和唤醒来实现信号量。
怎么做:用一个数据结构来存放睡眠的线程,在本实验中采用了LinkedList来存放,每次调用sleep()方法,会将当前线程放入LinkedList,然后让其睡眠;每次调用wake()方法会选择LinkedList里的一个线程将其唤醒;调用wakeAll()方法会将LinkedList里所有线程唤醒。
方法解释
- void sleep()方法
睡眠前先释放锁,然后将线程加入到等待队列中,然后睡眠即可,记得在最后申请锁,这是因为当唤醒该线程时,需要重新申请锁。 - void wake()方法
如果等待队列不为空,则取出一个线程将其唤醒。 - void wakeAll()方法
设置循环,只要等待队列不为空,则执行wake()方法。
关键点和难点
关键点:理解条件变量底层实现,可以通过看nachos已经给出的condition类的方法,分析其内部实现。
难点:理解条件变量的作用,锁的使用以及等待队列的用途。
实验测试代码
本实验测试:将用到condition的地方改为condition2,运行正常即可;
注:(由于在之后的实验用到了condition2,也可以与之后的task一起测试)
测试结果分析
将用到condition的地方全部换为condition2,运行正常。