操作系统课程设计实验报告proj1 联系客服

发布时间 : 星期三 文章操作系统课程设计实验报告proj1更新完毕开始阅读b4630f36b14e852459fb5796

}

// 系统关中断,当前线程休眠

oolean intStatus = Machine.interrupt().disable(); if (status != statusFinished) { }

Machine.interrupt().restore(intStatus);

// 调用另一个要调用的进程,将当前运行的线程加入到一个阻塞队列中。 waitForJoin.waitForAccess(currentThread); // 当前进程睡眠等待被调用进程结束 sleep();

public static void finish() {

Lib.debug(dbgThread, “Finishing thread: “ + // 系统关中断

Machine.interrupt().disable();// 当前进程运行结束的标志 Machine.autoGrader().finishingCurrentThread(); Lib.assertTrue(toBeDestroyed == null); // 表示当前进程要结束了

toBeDestroyed = currentThread;

// 当前进程的状态被修改为运行结束

currentThread.status = statusFinished; // 调用等待队列上的第一个进程 Kthread waitThread;

while ((waitThread = currentThread.waitForJoin.nextThread()) !=

currentThread.toString());

null) {// 唤醒等待队列上所有被阻塞的进程 waitThread.ready();

}

}

sleep();

2.2 Task 1.2实现条件变量 2.2.1题目要求

利用中断有效和无效所提供的原子性直接实现条件变量。我们已经提供类似的例子实例实现信号量。你要按此提供类似的条件变量的实现,不能直接利用信号量来实现(你可以使用lock,虽然它间接地调用了信号量)。在你完成时要提供条件变量的两种实现方法。你的第二种条件变量实现要放在nachos.threads.Condition2中。

5

2.2.2题目分析与实现方案

分析:条件变量使我们可以睡眠等待某种条件出现,是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使”条件成立”(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

方案:threads.Lock类提供了锁以保证互斥。在临界代码区的两端执行Lock.acquire() 和Lock.release() 即可保证同时只有一个线程访问临界代码区。条件变量建立在锁之上, 由threads.Condition实现,用来保证同步。每一个条件变量拥有一个锁变量。

(1)sleep()在条件变量的控制下sleep()函数自动释放相关锁并进入睡眠状态,直到令一个线程用wake()唤醒它,需要在函数的开始和结尾处关或允许中断保证原子性。当前线程必须拥有相关锁,阻塞进程在sleep()函数返回之前线程将会自动再次拥有锁。即调用这个方法的线程将自己挂起到等待队列,阻塞自己的同时将自己拥有的锁交出

去,之后等待锁的分配。拿到锁的线程再次拥有权限接受检验。 (2)wake()唤醒条件变量队列中第一个线程,在试验中利用从线程队列中取出线程用Kthread.ready()实现唤醒,加入就绪队列。(同样要在wake函数利用中断保证原子性)

(3)wakeall()函数的实现依赖于wake()。只需不断地wake挂在条件变量上的线程直到队列为空为止。

2.2.3关键点与难点

6

题目要求直接实现条件变量,不能直接利用信号量。所以互斥锁必须要有,它是线程们有秩序的接受条件变量检验的保证。等待队列必须要有,不满足条件的线程都要挂在上面。

2.2.4实现代码

public static void sleep() {

if (!waitQueue.isEmpty())

((Semaphore) waitQueue.removeFirst()).V(); }

public void wakeAll() {

while (!waitQueue.isEmpty()) wake(); }

Lib.assertTrue(conditionLock.isHeldByCurrentThread()); }

Lib.assertTrue(conditionLock.isHeldByCurrentThread());

if (currentThread.status != statusFinished)

// 锁住当前线程

currentThread.status = statusBlocked;

Lib.assertTrue(Machine.interrupt().disabled());

Lib.debug(dbgThread, “Sleeping thread: “ +

currentThread.toString());

// 运行下一个线程 runNextThread();

public void wake() {

2.3 Task 1.3 完成Alarm类 2.3.1题目要求

完成Alarm类,通过waitUntil(long x)方法实现。一个线程通过调用waitUntil(long x)方法将自己挂起,一直到经过x时间再被唤醒。这对现实操作很有用,例如,光标的周期闪烁。线程经过x时间后唤醒,

7

但不需要立刻运行,而是加入readyqueue中。不建立任何多余的线程实现waitUntil(),只需要修改waitUntil()中断处理程序和计时器。waitUntil()不受限于任何一个线程,任何线程可以调用它实现被挂起。

2.3.2题目分析与实现方案

分析:Alarm类使用硬件定时器提供抢占,并允许线程挂起到某个时间。分配的新闹钟设置机器的定时器中断处理程序实现本闹钟的回调,同时Nachos只在有一个计时器的情况下正常运行。

定时器中断处理程序被称为机器计时器定期(大约每500时钟周期)。当前线程产生后,如果有另一个必须运行的线程,则强制上下文切换。

当前线程睡眠至少x时间周期,在定时器中断处理程序中将其唤醒。当现在时间(current time) >= (WaitUntil called time)+(x)时,线程必须被唤醒(在调度准备集)在第一个定时器中断的产生时。

方案:(1)与Alarm类有关的是machine.Timer类,它在大约每500个时钟滴答使调用回调函数(由Timer.setInterruptHandler函数设置)。因此, Alarm类的构造函数中首先要设置该回调函数Alarm.timerInterrupt()。 timerInterrupt()方法在每一次timer产生时间中断时遍历队列,检查队列中的时间状态,当线程到了等待的时间就把线程从队列中取出放入就绪队列。

(2)waitUntil()方法使用了一个队列可以存放线程以及唤醒时间,这个队列以时间为序的有序队列。每次调用时,把当前线程和唤醒时间加入队列,等待唤醒。在调用waitUntil(x) 函数时, 首先得

8