Project 3 Tutorial - McMaster University
Download
Report
Transcript Project 3 Tutorial - McMaster University
Project 3 Tutorial
yuanhaoYU
Project Task
Implement class PriorityScheduler
complete an inner class PriorityQueue, whose instance stores queued thread
complete an inner class ThreadState utilized to record associated priority
make class PriorityScheduler functional.
solve Priority Donation problem
Scheduler
Scheduler is responsible for scheduling threads for all limited
resources, CPU, Lock, and Semaphore
Black Box Perspective:
the resource (e.g. class Lock) is responsible for adding thread to a queue of
scheduler
the resource requests scheduler return a thread from the queue
the queue here means a data structure storing threads waiting for the
resource
Scheduler
Resource, Queue, and Scheduler
Resource Lock
Lock
C
Thread C holds
the resource
queue
Resource Lock
contains a queue
instance
Z
When thread C releases the Lock,
Scheduler is utilized to decide which thread
in the queue should be the next one
H
Thread H waits for the
Lock; it actually
becomes a element of
the queue
RoundRobinScheduler
What’s Round Robin scheduler?
RoundRobinScheduler
public class RoundRobinScheduler extends Scheduler {
public RoundRobinScheduler() {
}
public ThreadQueue newThreadQueue(boolean transferPriority) {
return new FifoQueue();
}
private class FifoQueue extends ThreadQueue {
public void waitForAccess(KThread thread) {
Lib.assertTrue(Machine.interrupt().disabled());
waitQueue.add(thread);
}
public KThread nextThread() {
Lib.assertTrue(Machine.interrupt().disabled());
if (waitQueue.isEmpty())
return null;
return (KThread) waitQueue.removeFirst();
}
Construct a new FifoQueue
Instance in memory. It is usually
called by initialization of
resource
Basically, each kind scheduler
needs to design its own
corresponding queue;
Round Robin Scheduler makes
use of a FIFO queue: the
FifoQueue class is declared in
the Scheduler class;
Most importantly, the data
structure storing threads should
be a member of this class
called by resource and enqueuer
a thread
called by resource and request a
waiting thread
RoundRobinScheduler
public void acquire(KThread thread) {
Lib.assertTrue(Machine.interrupt().disabled());
Lib.assertTrue(waitQueue.isEmpty());
}
public void print() {
Lib.assertTrue(Machine.interrupt().disabled());
for (Iterator i=waitQueue.iterator(); i.hasNext(); )
System.out.print((KThread) i.next() + " ");
}
private LinkedList<KThread> waitQueue = new
LinkedList<KThread>();
}
}
resource inform queue that it is
occupied by a thread
In RR, just check some
conditions and do nothing
All threads waiting are actually
stored here in waitQueue
This data structure is
implemented by LinkedList
the whole class fifoQueue is
designed to make this
waitQueue act like a FIFO queue
RoundRobinScheduler
Resource, Queue, and Scheduler in RR
Lock
C
this queue is actually
a FIFO queue; All
threads are actually
stored in the
member variable
waitQueue of the
class FifoQueue
queue
Z
When thread C releases the Lock,
nextThread() function will be called by
resource. The FifoQueue will dequeuer
thread Z at front
H
Thread H and Z both
wait for the Lock; they
actually wait in the
waitQueue; We can
assume Z comes first
and H comes last.
Priority Scheduler
When resource requests a thread, priority scheduler should return
the one with the highest priority
Features:
each thread is assigned with a priority
always select the highest priority thread
FCFS with the same priority level
Priority Scheduler
When request a thread in queue, priority scheduler should return
the one with highest priority
Features:
each thread is assigned with a priority
always select the highest priority thread
FCFS with the same priority level
P3
P0
P2
P1
Priority Scheduling
0
5
11
14
22
Round Robin Scheduling
Priority Scheduler
There should be a place to store
the associated priority for each
thread
Thread with
priority 1
Thread Z with
priority 3
Lock
C
The data structure
acting the queue to
store threads should
be implemented;
The data structure
should be a member
of the queue class
queue
Z:3
1
1
1
1
H:4
When thread C releases the Lock, nextThread()
function will be called. Priority Scheduler should
return the one with highest priority H.
Thread H with priority 4
and Z both wait for the
Lock; We can still
assume Z comes first
and H comes last.
PriorityScheduler
There are two inner class in PriorityScheduler
Class PriorityQueue is responsible for storing waiting threads
Class ThreadState is responsible to record associated priority
PriorityScheduler
public class PriorityScheduler extends Scheduler {
public PriorityScheduler() {..}
public ThreadQueue newThreadQueue(boolean transferPriority) {..}
public int getPriority(KThread thread) {..}
public int getEffectivePriority(KThread thread) {..}
public void setPriority(KThread thread, int priority) {..}
public boolean increasePriority() {..}
public boolean decreasePriority() {..}
public static final int priorityDefault = 1;
public static final int priorityMinimum = 0;
public static final int priorityMaximum = 7;
protected ThreadState getThreadState(KThread thread) {..}
protected class PriorityQueue extends ThreadQueue {..}
protected class ThreadState {...}
}
called by resource and return a
instance of priority queue
Priority operation
In these functions, methods
(functions) of ThreadState will be
called to actually operate
priority, since the priority is
stored there
Inner class PriorityQueue
The data structure storing
threads should be a member
variable in the class
Inner class ThreadState
The data structure storing
priority should be a member
variable in the class
PriorityScheduler
protected class PriorityQueue extends ThreadQueue {
PriorityQueue(boolean transferPriority) {..}
public void waitForAccess(KThread thread) {..}
public void acquire(KThread thread) {..}
public KThread nextThread() {
Lib.assertTrue(Machine.interrupt().disabled());
// implement me
return null;
}
protected ThreadState pickNextThread() {
// implement me
return null;
}
public boolean transferPriority;
}
Implement these two functions to
make sure that it returns the
thread with highest priority
Attention: the data structure
storing threads needs to be
implemented
You could choose any suitable
data structure like heap,
linkedlist, but have to make sure
it act like priority queue
So, there may be some
additional functions you need to
implement
PriorityScheduler
protected class ThreadState {
public ThreadState(KThread thread) {..}
public int getPriority() {..}
public int getEffectivePriority() {} // implement me
public void setPriority(int priority) {} // implement me
public void waitForAccess(PriorityQueue waitQueue) {}
// implement me
public void acquire(PriorityQueue waitQueue) { } // implement me
protected KThread thread;
protected int priority;
}
The data structure storing priority
Consider how to store donated
priority
You can implement priority
donation here, since the priority
is stored here.
To donate priority, you may need
to find another thread holding a
queue; consider how to find that
thread
Priority Donation
When will it happen?
L:2
Lock 1
Iter2: C donates to L
2->7
queue
1
C:3
Z:4
1
C:3
1
1
Lock 2
Iter1: H donates to C
3->7
queue
1
1
1
1
1
H:3
Change priority from 3 to 7
Priority Donation
In Nachos, we can assume a thread only waits in one queue.
Logic:
Starts from a thread t0
Check if it waits in a queue
Donate its real priority to the thread t1 holding the queue
Restore priority
in the dequeue part (why?)
Compile and Execute
When Nachos initializes, a particular scheduler will be created
according to the configure file.
ThreadedKernel.scheduler = nachos.threads.PriorityScheduler
Under Proj2
Eclipse with Input:
-nachos.ag.ThreadGrader5
-nachos.ag.ThreadGrader6