CSS 430
FAQ on Program 3: Synchronization
Instructor: Munehiro Fukuda
Q1: I saw QueueNode.java in the ThreadOS directory, but cannot
read its content. What's that?
A: This class is used to instantiate synchronized objects that
are maintained by SyncQueue's private array. This is a part of
solution and thus inaccessible.
SyncQueue's private array maintains objects instantiated from
QueueNode.java. Each QueueNode object corresponds to a
different condition number and provides two synchronized methods, one
to put the calling thread to sleep on this condition and the other to
wake up a thread sleeping on this condition.
More specifically, SyncQueue.java's enqueueAndSleep( int
condition ) searches its private array for the QueueNode
object corresponding to this condition, and calls this
QueueNode's method that puts the current thread to sleep inside
this object. On the other hand, SyncQueue.java's
dequeueAndWakeup( int condition, int tid ) searches its private
array for the QueueNode object corresponding to this
condition, and calls another method of QueueNode that wakes up
a thread sleeping in this object.
Q2: May I use QueueNode.class?
A: No. You cannot use a part of key answer.
Q3: Are we supposed to build upon previous assignments?
For example are we supposed to include the shell.java and
Scheduler.java programs we did for previous assignments? If so which
scheduler are we supposed to use?
A: No, we aren't
You should use the original Shell.class and Scheduler.class I coded in
ThreadOS.
Q4: How should I test SyncQueue.java? How should I run my
Test2/Test3 on my Shell.java?
In the previous assignments, we have typed in "java Boot" and then at
the prompt "-->" we have typed in the name of the file to run. In this
assignment however you ask us to run our program from Shell. Does this
mean that we type "java Shell SomeProgram"?
A: Whenever you start ThreadOS, you have to type "java Boot". When
you run a user thread on Shell, you need to type "l Shell" and
thereafter type the name of a user thread.
% java Boot
threadOS ver 1.0:
Type ? for help
threadOS: a new thread (thread=Thread[Thread-3,2,main] tid=0 pid=-1)
-->l Shell
l Shell
threadOS: a new thread (thread=Thread[Thread-6,2,main] tid=1 pid=0)
Shell[1]% Test3
threadOS: a new thread (thread=Thread[Thread-8,2,main] tid=2 pid=1)
....
Q5: When I test my SyncQueue.java on ThreadOS, I got the following
result. Is it correct?
lisu@seawolf:~/430/ThreadOS> java Boot
threadOS ver 1.0:
Type ? for help
threadOS: a new thread (thread=Thread[Thread-3,2,main] tid=0 pid=-1)
-->l Test2
l Test2
threadOS: a new thread (thread=Thread[Thread-6,2,main] tid=1 pid=0)
-->threadOS: a new thread (thread=Thread[Thread-8,2,main] tid=2 pid=1)
threadOS: a new thread (thread=Thread[Thread-10,2,main] tid=3 pid=1)
A: No.
As soon as ThreadOS Loader invokes Test2, it displayed a new prompt,
(i.e., "-->" ). This means that ThreadOS Loader did not wait for the
termination of Test2.
Q6: In the specification of SyncQueue.java, you said we should use
wait and notify. How can we know which thread will wake up if we only
use notify?
A: The SyncQueue object itself should not call wait() nor notify() directly. You should make the wait()
and notify() calls in the specific QueueNode object corresponding to the condition.
Otherwise you cannot distinguish different conditions.
Q7: Can I use notifyAll instead?
A: No. You should wake up only one thread.
Q8: How can we make sure to wake up the thread in the
first-come-first service order?
A: You don't have to enforce the FCFS order
Q9: I got a message that is "illegal monitor state exception." What's
wrong with my code?
public void sleep( ) {
try{
currentThread.wait( );
}catch (InterruptedException e){}
}
A: wait( ) and notify( ) must be used inside a synchronized
method. Also, don't add any keyword or object name to wait( ) and
notify( ).
public synchronized void sleep( ) {
try{
wait( );
}catch (InterruptedException e){}
}
Q10: I thought I implemented SyncQueue.java, but I found that
Test2.java had not been always woken up even after the termination of
all its five child threads. I have no clue.
A: For each condition, you have to maintain a Vector queue of child
thread IDs in QueueNode.java.
When a child thread calls SyncQueue.dequeueAndWakeup( ) that calls
QueueNode.wakeup( ) or something, it enqueues its TID in this Vector
queue of thread IDs. When a parent thread calls
SyncQueue.enqueueAndSlee( ) that calls QueueNode.sleep( ) or
something, it checks if the Vector queue of child thread IDs is
empty. If so, it puts itself to sleep. Upon a wake-up, it checks this
TID queue and picks up the first ID from this queue as a return
value.
If all your five child threads have been terminated first, Test2.java
will not sleep at all even when it has called SysLib.join( ) five
times.
Q11: When you refer to "running time" do you mean execution time or
turnaround time?
A: Test3.java should measure the time elapsed from the spawn to the
termination of its child threads.
You may precisely measure the execution time and turnaround time for
each of TestThread3a.java and TestThread3b.java or (a
computation-intensive and an I/O intensive thread,) too.
Q12: How can I get the current thread's TCB?
A: Use Scheduler.getMyTcb( ).
Scheduler.getMyTcb( ) returns the current thread's TCB. Assuming that
the curTcb refers to the current thread's TCB obtained from
Scheduler.getMyTcb( ), you can get the current thread's id and parent
id by calling curTcb.getTid( ) and curTcb.getPid( ) respectively.
Q13: I'm not sure how to use the rawread, rawwrite, and sync
method calls.
I tried to write a little thread to test rawwrite, but I got an
ArrayOutOfBounds Error from Disk.run() when it tries to do an array
copy.
public class newTest extends Thread {
public void run () {
byte[] bytes = new byte[512];
String str = "message";
bytes = str.getBytes();
SysLib.rawwrite( 1, bytes );
SysLib.exit( );
}
}
A: Be reminded that the assignment in Java is regarded as
substituting the left-hand-side variable with a reference to the
right-hand-side variable.
In the above example, bytes originally got an array of 512 bytes,
however it was substituted with a reference to "message" whose size is
7 * 2 bytes, (i.e., 14 bytes). (Recall that a character needs two
bytes in Java.) So, at the time when you called rawwrite, the bytes
array had only 14bytes other than 512 bytes. That's the reason why
rawwrite went mad.
Q14: I got an illegal monitor state exception.
Java.lang.IllegalMonitorStateException: current thread not owner
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:426)
at SyncQueue.enqueueAndSleep(SyncQueue.java:56)
at Kernel.interrupt(Kernel.java:98)
at SysLib.join(SysLib.java:10)
at Loader.run(Loader.java:48)
at java.lang.Thread.run(Thread.java:536)
I have done some debugging and this code is causing the error:
public void enqueueAndSleep( int condition ) {
Thread t = Thread.currentThread( );
try {
this.wait( );
} catch ( InterruptedException e ) {
SysLib.cerr( e.toString( ) + "\n" );
}
QueueNode node = new QueueNode(t, condition);
addNode(node);
} // End endqueueAndSleep
A: You should simply call wait( ). Don't use "this.wait( )".
See also the answer to Q9.