1、Whats wrong?public int listen() lock.acquire(); if (!present) / 如果没有留言 empty.sleep(); / 则睡眠/ 取得留言int word = buffer;present = false; / 唤醒正在等待发言的人full.wake(); lock.release();return word;public void speak(int word) lock.acquire();if (present) / 如果已有留言 full.sleep(); / 则睡眠/ 留言buffer = word;present = true
2、;/ 唤醒正在等待接受留言的人empty.wake();lock.release();Wrong or Not?public class KThread ./* Unique identifer for this thread. Used to deterministicallycompare threads. */ private int id = numCreated+; /* Number of times the KThread constructor was called. */private static int numCreated = 0;.How to Read code?C
3、ase Study: KThread和 TCB的构造顺序分析u 一个 KThread必然有一个 TCB吗?u 每个 TCB必然在运行一个 KThread吗?u 先有第一个 TCB,还有先有第一个 KThread?KThread和 TCB的构造顺序分析 先有鸡还是先有蛋?首先被构造出的是 TCB, 在 Machine.main完成各种环境初始化后,最后一句写的是:new TCB().start(new Runnable() public void run() autoGrader.start(privilege); );其实, autoGrader.start会构造一个 Kernel的实例 (根
4、据 Nachos.coff的设置,目前就是 ThreadKernel),并且 调用 Kernel.initialize令其自我初始化转入 ThreadKernel.initialize, ThreadKernel首先装入自己需要的Scheduler和 FileSystem, 然后鬼使神差般地写了一句:new KThread(null);这就是最早的 KThread的实例。(我们称它叫 “new KThread No1”)KThread和 TCB的构造顺序分析 new KThread(null)?注意这么构造 KThread是 可疑 的。因为在过程里没有保存对这个实例的引用,所以这个 KThre
5、ad永远没有机会被 fork()!public void initialize(String args) new KThread(null); / “new KThread No1” 检查整个工程,我们没有发现其他地方有这么写的,这么做的目的何在?我们需要看看 KThread的构造函数干了什么: if (currentThread != null) / currentThread是静态全局变量,/ 其初值默认为空tcb = new TCB(); else / 可见第一次进 KThread()是执行这里KThread和 TCB的构造顺序分析 if (currentThread != null)?
6、 / 接上 else readyQueue = ThreadedKernel.scheduler.newThreadQueue(false);readyQueue.acquire(this);currentThread = this; tcb = TCB.currentTCB(); / 这句话非常重要,我们在下面会分析到createIdleThread();进入了 ”else”这个模块之后, currentThread被立即赋值了,结合上下文的语意,我们可以推测这个 ”else”模块不会被执行第二次。于是我们断言:首次调用 KThread的构造函数,作用仅仅是初始化!KThread和 TCB的
7、构造顺序分析 改造 “new KThread No1”根据上述分析, “new KThread No1” 和直觉上大相径庭,似乎改写成KThread.initialize(); 会更自然一点,那为何需要这么写? public void initialize(String args) new KThread(null); / 是不是 KThread.initialize(); 更自然? (提示: currentThread = this 这句话揭示了问题的答案 )我们的目标是研究每个 KThread是如何和一个 TCB绑定并且运行起来的, “new KThread No1”没有给我们提供有用的东
8、西。 幸运的是,它的 一个子过程: createIdleThread引起了我们的注意: KThread和 TCB的构造顺序分析 IdleThreadprivate static void createIdleThread() idleThread = new KThread(new Runnable() public void run() while (true) yield(); ); / “new KThread No2”idleThread.setName(“idle”).fork();我们又看到一句 new KThread(.); 可以叫作 “new KThread No2”。与”No
9、1” 不同,这一次 currentThread 不为 null了,于是, KThread的构造函数只会执行一句话:if (currentThread != null) tcb = new TCB(); KThread和 TCB的构造顺序分析 creatIdleThreadprivate static void createIdleThread() idleThread = new KThread(new Runnable() public void run() while (true) yield(); ); / “new KThread No2”idleThread.setName(“idl
10、e”).fork();我们又看到一句 new KThread(.); 可以叫作 “new KThread No2”。与”No1” 不同,这一次 currentThread 不为 null了,于是, KThread的构造函数只会执行一句话:if (currentThread != null) tcb = new TCB(); KThread和 TCB的构造顺序分析summaryinterrupt().enable()Main TCB Created By Machine():kernel.initializenew KThread(null)kernel.run();kernel.terminate();createIdleThreadcurrentThread = this tcb = TCB.currentTCB tcb=new TCB()初始化内核开启中断启动内核中止内核初始化全局变量建立空闲线程内核自检 kernel.selfTest();TCB Created By Main TCB:yield();yield();tcb=new TCB()Boat.selfTest();tcb=new TCB() process.execute (shellProgram