Open main menu

lensowiki β

Changes

Computer Science/162/proj1

534 bytes added, 03:51, 20 February 2023
m
}</pre>}}
==WaitUntil{{c|waitUntil()}}==
===Implementation===
;New state variables
Alarm has a new instance variable, {{c|waitingThreads}}, which is a Java {{c|PriorityQueue }} of waiting threads with the target wake time as their priority. It also contains a new inner class named waitingThread{{c|WaitingThread}}, which contains a reference to a {{c|KThread }} and its associated {{c|wakeTime}}. The {{c|PriorityQueue waitingThreads }} will be populated with instances of this inner class.
;Implementation details
* {{c|waitUntil() }} creates a new instance of {{c|waitingThread}}, which will associate the currentThread current thread with the give given time argument. It will then add this {{c|waitingThread }} instance to the {{c|PriorityQueue }} and put the current thread to sleep. This method is atomic. * {{c|timerInterrupt() peek }} peeks at the first {{c|WaitingThread }} in the {{c|waitQueue }} and check checks if its associated wake time is less than or equal to the current time. If it is, this method will pop the {{c|WaitingThread }} off the {{c|waitQueue }} and wake the associated thread. This process is repeated until the wake time of the first {{c|WaitingThread }} is greater than the current time.
===Testing===
* Have the timer interrupt print a debug statement, and have timed threads print the times they go to sleep and when they have woken up. Verify that they wake up relatively close to their expected exit wake time.
* Make sure threads called with illegal times return immediately. Test threads that go to sleep chronologically in order (1, 500, 1050) as well as threads that go to sleep with the same times (50, 50) and threads that go to sleep in reverse order (500, 250). Verify they all wake up when they are supposed to.
Re-enable interrupts;
}</pre>}}
 
{{c|<pre>timerInterrupt(){
Wake a waiting listener;
}
Sleep as an active speakerwaiting to return;
AS--;
AL--;
Wake a waiting speaker;
}
Sleep as an active listenerwaiting to return;
AL--;
AS--;
==Priority Scheduler==
===Implementation===
;New state variables
* {{c|PriorityQueue.holder}} - this ThreadState corresponds to the holder of the resource signified by the
* {{c|PriorityQueue.waitQueue}} - an ArrayList of ThreadStates waiting on this resource. Unsorted.
* {{c|PriorityQueue.dirty}} - set to true when a new thread is added to the queue, or any of the queues in the waitQueue flag themselves as dirty.
* {{c|PriorityQueue.effective}} - the cached highest of the effective priorities in the waitQueue. This value is invalidated while dirty is true.
The idea here is * {{c|ThreadState.myResources}} - collection of PriorityQueues that signify the Locks or other resources that Threads keep track this thread currently holds.* {{c|ThreadState.waitingOn}} - collection of the PriorityQueues corresponding to both the resources that they are currently holding and those that they want this thread has attempted to holdacquire but could not.* {{c|ThreadState. We can do effective}} - the cached effective priority of this via hooking PriorityQueue's waitForAccess, acquire, and nextThreadthread.this value is invalidated when dirty is true Once we have * {{c|ThreadState.dirty}} - set to true when this, every time a thread tries to wait on a queue, or takes control of a queue, we can tell that queue that its overall effective 's priority may have is changed, and it can in, turn tell the thread that currently holds the resource that or when one of the PriorityQueues it holds may have had its priority changed. That holder can queues in turn tell the same to the PriorityQueues that it is waiting on, and so on. Eventually a thread holding a resource that everyone needs, but with a low priority will be marked for priority recalculationmyResources flags itself as dirty.
At this point recalculation is simple. ;Implementation overviewThe effective priority of a thread idea here is the maximum that {{c|Thread}}s keep track of its own actual priority and the priorities of all {{c|PriorityQueue}}s corresponding to both the PriorityQueues resources that it they are currently holdsholding and those that they want to hold. The effective priority of a We can do this via hooks in {{c|PriorityQueue is the maximum effective priority of all the threads waiting on it }}'s {{c|waitForAccess(if the queue is supposed to donate priority)}}, {{c|acquire}}, and so on and so forth in this mutually recursive manner{{c|nextThread}} methods.
;New state variables*'''PriorityQueue''' – {{c|ThreadState holderOnce we have this, every time a thread tries to wait on a queue, ArrayList<ThreadState> waitQueueor takes control of a queue, int we can tell the queue that its overall effectivepriority may have changed, boolean dirty}}<br />*'''ThreadState''' – and it can, in turn, tell the thread that currently holds the resource that one of the {{c|int effective, boolean dirty, HashSet<PriorityQueue> myResources, WaitingOn}}<br /> PriorityQueues it holds may have had its priority changed.That holder - this ThreadState corresponds can in turn tell the same to the holder of the resource signified by the {{c|PriorityQueue.waitQueue - an ArrayList of ThreadStates }}s that it is waiting on this resource. Unsorted.PriorityQueue, and so forth.dirty - set to true when Eventually a new thread is added to the queue, or any of the queues in the waitQueue flag themselves as dirty.PriorityQueue.effective - the cached highest of the effective priorities in the waitQueue. This value which is invalidated while dirty is true. ThreadState.myResources - collection of PriorityQueues holding a resource that signify the Locks or other resources that this thread currently holds.ThreadState.waitingOn - collection of PriorityQueues corresponding to resources that this thread everyone needs, but has attempted to acquire but could not.ThreadState.effective - the cached effective a low priority, will be marked for priority of this thread. this value is invalidated when dirty is trueThreadState.dirty - set to true when this thread's recalculation and thus priority is changed, or when one of the queues in myResources flags itself as dirtyescalation.
At this point, recalculation is simple. The effective priority of a thread is the maximum of its own actual priority and the priorities of all the {{c|PriorityQueue}}s that it currently holds. The effective priority of a {{c|PriorityQueue}} is the maximum effective priority of all the threads waiting on it (if the queue is supposed to donate priority), and so on and so forth in a mutually recursive manner.
;Implementation details
* {{c|PriorityQueue.nextThread()}}* :This method retrieves and removes the highest priority thread off the Priority-Time {{c|ArrayList}}. It then flags the previous holder of this resource as {{c|dirty}}, and removes the queue from that holder's resource list. It then sets the retrieved thread to this queue's new {{c|holder}}, and flags that thread as {{c|dirty }} as well.* {{c|PriorityQueue.acquire(KThread thread)}}* :Sets the {{c|holder }} of this queue to the specified thread, bypassing the queue. Resets previous {{c|holder }} and sets {{c|dirty }} flags as in {{c|nextThread()}}.* {{c|PriorityQueue.pickNextThread()}}* :Simply retrieves the highest priority thread off this queue.* {{c|PriorityQueue.setDirty()}}* :Set this queue's {{c|dirty }} flag, and calls {{c|setDirty }} on the current holder of this thread.* {{c|PriorityQueue.getEffectivePriority()}}* :If this queue is "{{c|dirty"}}, returns the maximum of each of the ThreadStates{{c|ThreadState}}s{{c|.getEffectivePriority() }} in this queue. Those calls in turn become mutually recursive when they call {{c|getEffectivePriority ()}} on the {{c|PriorityQueues }} in their myResrouces{{c|myResources}}.* {{c|ThreadState.setPriority() }}* :This method will change the actual priority of the thread associated with the {{c|ThreadState}}. It then does calls {{c|setDirty() }} on this thread.* {{c|ThreadState.setDirty()}}* :Sets the {{c|dirty }} flag on this thread, then calls {{c|setDirty()}} on each of the PriorityQueues {{c|PriorityQueue}}s that the thread is waiting for, does setDirty on them. Mutually recursive.* {{c|ThreadState.getEffectivePriority}}* :Like the analogue of this function in {{c|PriorityQueue}}, returns the (cached) priority if this thread is not {{c|dirty}}; otherwise, otherwise recalculates by returning the max of the effective priorities of the PriorityQueues {{c|PriorityQueue}}s in {{c|myResources}}.
===Testing===
===Pseudocode===
;PriorityQueue {{c|<pre> public void waitForAccess(KThread thread) add this thread to my waitQueue thread.waitForAccess(this) public void acquire(KThread thread) if I have a holder and I transfer priority, remove myself from the holder's resource list thread.acquire(this) public KThread nextThread() if I have a holder and I transfer priority, remove myself from the holder's resource list if waitQueue is empty, return null ThreadState firstThread = pickNextThread(); remove firstThread from waitQueue firstThread.acquire(this); return firstThread } public int getEffectivePriority() if I do not transfer priority, return minimum priority if (dirty) effective = minimum priority; for each ThreadState t in waitQueue effective = MAX(effective, t.getEffectivePriority()) dirty = false; return effective; public void setDirty() if I do not transfer priority, there is no need to recurse, return dirty = true; if I have a holder, holder.setDirty() protected ThreadState pickNextThread() ThreadState ret = null for each ThreadState ts in waitQueue if ret is null OR ts has higher priority/time ranking than ret set ret to ts return ret;
public int getEffectivePriority() if I do not transfer priority, return minimum priority if (dirty) effective = minimum priority; for each ThreadState {t in waitQueue effective = MAX(effective, t.getEffectivePriority()) dirty = false; return effective;
public int getPriorityvoid setDirty() if I do not transfer priority, there is no need to recurse, return non-donated priority. dirty = true; public int getEffectivePriority if I have a holder, holder.setDirty() if protected ThreadState pickNextThread(dirty) { effective ThreadState ret = non-donated prioritynull for each PriorityQueue pq that I am currently holdingThreadState ts in waitQueue effective = MAX(effective, pq.getEffectivePriority) if ret is null OR ts has higher priority/time ranking than ret } set ret to ts return effectiveret;</pre>}}
;ThreadState{{c|<pre>public int getPriority() return non-donated priority. public int getEffectivePriority() if (dirty) { effective = non-donated priority for each PriorityQueue pq that I am currently holding effective = MAX(effective, pq.getEffectivePriority) } return effective; public void setPriority(int priority) { set non-donated priority to the argument setDirty(); } public void setDirty() { if already dirty return dirty = true; for each of the PriorityQueues pq I am waiting on, pq.setDirty } public void waitForAccess(PriorityQueue waitQueue) { add the waitQueue to my waitingOn list if the waitQueue was previously in myResources, remove it and set its holder to null. if waitQueue has a holder, set the queue to dirty to signify possible change in the queue's effective priority public void acquire(PriorityQueue waitQueue) { add waitQueue to myResources list if waitQueue was in my waitingOn list, remove it setWaitQueue's holder to me setDirty(); }
public void acquire(PriorityQueue waitQueue)
add waitQueue to myResources list
if waitQueue was in my waitingOn list, remove it
setWaitQueue's holder to me
setDirty();</pre>}}
==Boat.java==
In addition, each thread has a local variable to keep track of which island the person is currently on.
;Basic ideaImplementation overview
If there are no children on Molokai or if there are no adults left on Oahu, two children from Oahu will pilot over and one will return to Molokai. If there is a child on Molokai, an adult will pilot over to Molokai and the child will bring the boat back to Oahu. This process, carried to completion eventually results in all of the adults and children on Molokai. Each thread will attempt to acquire the lock (which essentially represents control over the boat). If the thread can perform one of the tasks fitting for the current state of the world, it executes it. Otherwise, it will go to sleep on the condition variable corresponding to its current role and location.
;Algorithm Implementation details
Each child will begin running on Oahu and try to acquire the lock.
==Design questions==
;Why is it fortunate that we did not ask you to implement priority donation for semaphores?
:Be damned Currently, each time a thread acquires a lock or calls {{c|join()}}, we know who is currently holding the resource. This allows us to donate priority to this single resource if I knowa higher-priority thread begins waiting on it. With semaphores, this is not possible for initial values greater than 1, because the last thread to successfully "acquire" the semaphore will not necessarily be the one with the lowest priority. The implementation would need to change to keep track of all threads that are actually using the semaphore currently and thus be able to determine which of those has the lowest priority and needs to "receive" a donation. Anyone?
;A student proposes to solve the boats problem by use of a counter, AdultsOnOahu. Since this number isn't known initially, it will be started at zero, and incremented by each adult thread before they do anything else. Is this solution likely to work? Why or why not?
:No, because there is no way of enforcing the fact that everyone will increment it before they do anything else.
1,277
edits