最近,操作系统课程设计使用伯克利大学的Nachos做为实验平台,老师也照搬伯克利的Project要求,开始我们的操作系统课程设计。
结合自己的学习过程和课设要求,我觉得对Nachos的学习首先应该从KThread.java入手,首先应该看明白这个类的所有函数的意思。
这个主要是为第一个proj,实现join()函数做准备。 Join()方法的含义:当前线程a在运行,执行b.join(),则a阻塞,直到线程b结束,a继续执行。
具体的要求有:Join函数的作用即为等待某线程运行完毕。当前线程 (唯一一个正在运行的线程) A调用另一个线程 (处于就绪状态) B的join函数时 (A 和 B 在Nachos中均为KThread类型对象),A被挂起,直到B运行结束后, join函数返回,A才能继续运行。注意在一个KThread对象上只能调用一次join,且当前线程不能对自身调用join。Waits for this thread to finish. If this thread is already finished, return immediately. This method must only be called once; the second call is not guaranteed to return. This thread must not be the current thread.
1 public void join() { 2 3 Lib.debug(dbgThread, "Joining to thread: " + toString()); 4 // 等待另外一个线程结束的这个线程不能是线程自己 5 Lib.assertTrue(this != currentThread); 6 7 if (this.status == statusFinished) 8 return; 9 10 boolean intStatus = Machine.interrupt().disable(); 11 12 if (joinQueue == null) { 13 joinQueue = ThreadedKernel.scheduler.newThreadQueue(true); 14 // Notify this thread queue that a thread has received access,without going through request() and nextThread() 15 joinQueue.acquire(this); 17 } 18 // Notify this thread queue that the specified thread is waiting for 19 // access 20 joinQueue.waitForAccess(currentThread); 21 KThread.sleep(); 22 Machine.interrupt().restore(intStatus); 23 }
为此,我设置了一个KThread的队列joinQueue,当B调用join函数时,将正在执行的A线程放入joinQueue,只有在B执行完后,在finish()里面会将队列中的A线程状态变为ready,从而继续执行A线程,具体finish()实现的代码如下:
1 public static void finish() { 2 Lib.debug(dbgThread, "Finishing thread: " + currentThread.toString()); 3 4 Machine.interrupt().disable(); 5 6 Machine.autoGrader().finishingCurrentThread(); 7 8 Lib.assertTrue(toBeDestroyed == null); 9 toBeDestroyed = currentThread; 10 11 currentThread.status = statusFinished; 12 13 KThread joinedKThread; 14 if (currentThread.joinQueue != null) 15 while ((joinedKThread = currentThread.joinQueue.nextThread()) != null) 16 joinedKThread.ready(); 17 sleep(); 18 }
后续测试程序如下:
package nachos.threads; import nachos.machine.*; public class KThreadTest { public KThreadTest() { } public static void simpleJoinTest() { KThread A_thread = new KThread(new KThreadTest.A_thread(5)); KThread B_thread = new KThread(new KThreadTest.B_thread(A_thread)); B_thread.fork(); B_thread.join(); } public static class B_thread implements Runnable { B_thread(KThread joinee) { this.joinee = joinee; } public void run() { System.out.println("B_thread 就绪"); System.out.println("Forking and joining A_thread..."); this.joinee.fork();//Causes this thread to begin execution. this.joinee.join();//启动a线程,阻塞b线程 System.out.println("B_thread 执行结束"); } private KThread joinee; } public static class A_thread implements Runnable { A_thread(int num) { this.num = num; } public void run() { System.out.println("A_thread 就绪"); System.out.println("A_thread开始执行"); // This should just kill some cycles for (int i = 0; i < this.num; ++i) { System.out.println("A_thread 循环 第" + i + " 次"); KThread.currentThread().yield(); } System.out.println("A_thread 执行结束"); } private int num; } }