modern-multithreading-c-java
.pdf
EXERCISES |
245 |
EXERCISES
4.1.Modify monitor r gt w 1SC in Listing 4.10 so that it uses the cascaded wakeup technique of Listing 4.18 to wake up waiting readers.
4.2.Write an SU monitor that implements the strategy R<W.2. This strategy gives writers a higher priority than readers, except that when a writer arrives, if it is a lead writer (i.e., no writer is writing or waiting), it waits until all readers that arrived earlier have finished.
4.3.In Section 4.9, threads execute exitMonitor() before making a nested monitor call and enterMonitor() when the call returns. This gives returning threads the same priority as new threads that are trying to enter the monitor for the first time. Consider using the reentry queue to give returning threads higher priority than new threads. Returning threads call method reenterMonitor():
exitMonitor();
/* nested monitor call;*/ reenterMonitor();
(a)Assume that methods exitMonitor() and reenterMonitor() are implemented as follows:
exitMonitor(): if (reentryCount >0) reentry.V(); else mutex.V(); reenterMonitor():reentry.P();
Describe the problem with this implementation.
(b)Assume that methods exitMonitor() and reenterMonitor() are implemented as follows:
exitMonitor(): if (reentryCount >0) reentry.V(); else mutex.V(); reenterMonitor():reentryCount ++ reentry.P();reentryCount --;
Describe the problem with this implementation.
(c)Show how to implement method reenterMonitor() correctly, and show any modifications that need to be made to the other methods in class monitorSU.
4.4.The following implementation of methods waitC() and signalC() for an SC monitor is incorrect:
public void waitC() { ++numWaitingThreads; threadQueue.VP(mutex); mutex.P();
246 |
MONITORS |
--numWaitingThreads;
}
public void signalC() {
if (numWaitingThreads > 0) threadQueue.V();
// continue in the monitor; perhaps send more signals
}
Why is this implementation incorrect? Consider what can happen if two successive signal operations are performed on a condition variable on which one thread is waiting.
4.5.Section 4.7 shows toolboxes for SC and SU monitors in Java. These toolboxes use a binarySemaphore named mutex :
(a)In the SC toolbox, can mutex be a mutexLock instead of a binarySemaphore? Explain your answer.
(b)In the SC toolbox, can mutex be a mutexLock instead of a binarySemaphore? Explain your answer.
If you answer “no,” be sure to describe a scenario that causes a problem (e.g., “Thread1 enters the monitor and does a wait, Thread2 enters the monitor . . .”).
4.6.When semaphore programs are being replayed, we assume that all semaphores are FCFS (threads are awakened by V operations in the same order that they were blocked in P operations). This assumption is necessary to make P and V operations deterministic. The monitor toolboxes in Section 4.5 use binarySemaphores. A solution for replaying simple M- sequences is presented in Section 4.7. Is this solution guaranteed to work if the semaphores in the toolboxes are not FCFS? Specifically:
(a)If semaphore mutex in the SC toolbox is not FCFS, is the solution guaranteed to work?
(b)If semaphore mutex in the SU toolbox is not FCFS, is the solution guaranteed to work?
(c)If semaphore reentry in the SU toolbox is not FCFS, is the solution guaranteed to work?
Explain your answers.
4.7.The sleeping barber problem. A barbershop consists of a waiting room with n chairs, and the barber room containing the barber chair. If there are no customers to be served, the barber goes to sleep. If a customer enters the barbershop and all the chairs are occupied, the customer leaves the shop. If the barber is busy, but chairs are available, the customer sits in one of the free chairs. If the barber is asleep, the customer wakes up the barber. Here is a semaphore solution to the problem.
EXERCISES |
247 |
binarySemaphore mutex(1);
countingSemaphore customer(0), done(0), chair(0); int waiting = 0; // count of waiting customers barber() {
while (true) { |
|
customer.P(); |
// wait for or get the next customer |
mutex.P(); |
|
--waiting; |
// one fewer waiting customer |
chair.V(); |
// show customer to chair |
mutex.V(); |
|
sleep(...); |
// cut hair |
done.V(); |
// tell the customer that the haircut is done |
} |
|
} |
|
customer() { |
|
while (true) { |
|
mutex.P(); |
|
if (waiting < numChairs) { |
|
++waiting; |
|
customer.V(); |
// wake up the barber if he’s asleep |
mutex.V(); |
|
chair.P(); |
// wait for the barber to show you to a chair |
done.P(); |
// wait until the barber says that you’re done |
} |
|
else mutex.(); |
|
}
}
The barber waits on semaphore customer for the next customer. When a customer is available, the barber decrements the count of waiting customers and signals the semaphore chair, allowing the next customer into the barber chair for a haircut. A customer who needs a haircut accesses the count of waiting customers and increments the count if there is a free chair in the waiting room. After entering the waiting room, a customer signals the semaphore customer, which wakes up the barber, and then waits on semaphore chair for a chair. The barber releases the customer with the done semaphore.
(a)Write an SU monitor that solves the sleeping barber problem.
(b)In method barber() of the semaphore solution, customer.V() occurs before mutex.V(). Is the program correct if customer.V() occurs immediately after mutex.V()? Explain.
(c)Does numChairs include the barber chair? Explain.
248 |
MONITORS |
4.8.Develop monitor solutions to the unisex bathroom problem. Your monitor should have four methods: enterMen(), exitMen(), enterWomen(), exitWomen(), and it should use the SU signaling discipline.
(a)Develop a monitor solution that allows any number of men or any number of women (but not both) in the bathroom at the same time. Your solution should ensure the required exclusion and avoid deadlock, but it need not be fair (i.e., some people may never get to use the bathroom).
(b)Develop a monitor solution that ensures fairness:
žAll men and women eventually get to use the bathroom.
žWhen the last man in the bathroom exits, all women who are currently waiting are allowed to enter the bathroom.
žWhen the last woman in the bathroom exits, all men who are currently waiting are allowed to enter the bathroom.
žIf men are in the bathroom, another man cannot enter the bathroom if women are waiting.
žIf women are in the bathroom, another women cannot enter the bathroom if men are waiting.
4.9.Develop an SU monitor solution to the following strategy for the readers and writers problem: Many readers or one writer with writers having a higher priority, except that at the end of writing, waiting readers have a higher priority than waiting writers. (That is, readers that are waiting when the write ends are allowed to read, but not the readers that arrive afterward.) Use methods startRead(), endRead(), startWrite(), and endWrite() like the solution in Section 4.2.4. Note that this strategy does not create starving readers or writers. A waiting writer does not starve since the number of readers allowed to proceed at the end of each writing is finite. A waiting reader does not starve since it will be allowed to proceed when the next write ends.
4.10.Suppose that monitor threadOrderer below uses an SC toolbox that is implemented without VP() operations.
(a)Describe how monitor threadOrderer orders the operations by the three threads.
(b)SC toolbox “monitorNoVP” is like the SC toolbox presented in Section 4.7 except that it uses separate V() and P() operations in place of a VP() operation. Does this cause any problems in monitor threadOrderer? If so, show a scenario that illustrates the problem.
import java.util.*; public final class Order {
public static void main (String args[]) { threadOrderer c = new threadOrderer(); orderedThread t0 = new orderedThread (c,0);
EXERCISES |
249 |
orderedThread t1 = new orderedThread (c,1); orderedThread t2 = new orderedThread (c,2); t0.start(); t1.start(); t2.start();
}
}
final class orderedThread extends Thread {
//a simple thread that calls operations beginOp and endOp of a monitor. private int num; // ID of thread.
threadOrderer c; // monitor to call
orderedThread (threadOrderer c, int num) {this.c = c; this.num = num; } public void run () {
try {
for (int i=0; i<10; i++) { Thread.sleep((long)(Math.random()*1000)); c.beginOp(num);
System.out.println(num+ "Did op"); c.endOp();
}
} catch (InterruptedException e) {}
}
}
final class threadOrderer extends monitorSCNoVP { private int next=0;
private int wakeCount=0; // number of waiting threads that have been // awakened
private int waitCount=0; // number of waiting threads private int[] sequence;
private conditionVariable myTurn = new conditionVariable(); public threadOrderer() {
sequence = new int[3]; // three threads in the program sequence[0] = 2; sequence[1] = 1; sequence[2] = 0;
}
public void beginOp(int ID) { enterMonitor();
if (ID != sequence[next]) { ++waitCount; System.out.println(ID + "waiting");
myTurn.waitC(); // first waitC() while (ID != sequence[next]) {
++wakeCount;
if (wakeCount < waitCount) { myTurn.signalC(); // wake up next thread
myTurn.waitC(); |
// second waitC() |
} |
|
else |
|
250 |
MONITORS |
myTurn.waitC(); |
// third waitC(). All threads have had a |
turn |
|
} |
|
-- waitCount; |
|
} |
|
exitMonitor(); |
|
} |
|
public void endOp() { |
|
enterMonitor(); next = (next+1) %3;
System.out.println("waitCount is " + waitCount); if (waitCount>0) {
wakeCount=0; |
|
myTurn.signalC(); |
// wake up first thread |
} |
|
exitMonitor(); |
|
}
}
4.11.Below is an implementation of the strategy R<W.2 using SC monitors. This strategy allows concurrent reading and generally gives writers a higher priority than readers. Readers have priority in the following situation: when a writer requests to write, if it is a lead writer (i.e., no other writer is writing or waiting), it waits until all readers that arrived earlier have finished reading.
(a)Is this implementation correct? If not, give a scenario that demonstrates any errors that you found. Methods startRead() and startWrite() contain if-statements that determine whether a waitC() operation is executed.
(b)If these if-statements are changed to while-loops, is the implementation correct? If not, give a scenario that demonstrates any errors that you found.
(c)If you believe that the implementations in parts (a) and (b) are incorrect, show how to modify the implementation below to correct it.
public final class r_lt_w_2 extends monitorSC {
int readerCount = 0; // number of active readers boolean writing = false;
int waitForReaders = 0; // if waitForReaders > 0, lead writer waits // for readers that arrived earlier
conditionVariable readerQ = new conditionVariable(); conditionVariable writerQ = new conditionVariable(); public void startRead() {
EXERCISES |
251 |
enterMonitor();
if (writing || !(writerQ.empty()) || waitForReaders > 0) readerQ.waitC();
++readerCount;
if (waitForReaders>0) waitForReaders--;
exitMonitor();
}
public void endRead() { enterMonitor(); --readerCount;
if (readerCount==0) writerQ.signalC();
exitMonitor();
}
public void startWrite() { enterMonitor();
if (readerCount > 0 || writing || waitForReaders > 0) writerQ.waitC();
writing = true; exitMonitor();
}
public void endWrite() { enterMonitor(); writing = false;
if (!(writerQ.empty())) writerQ.signalC();
else {
waitForReaders = readerQ.length(); for (int i = 1; i <= waitForReaders; i++)
readerQ.signalC();
}
exitMonitor();
}
}
4.12.Write a correct SC monitor implementation of strategy R<W.2. Your monitor should have methods request(int ID, boolean isReadRequest), startRead(int ID), endRead(), startWrite(int ID), and endWrite(). Reader and writer threads pass their IDs on calls to request(ID,isReadRequest), startRead(ID), and startWrite(ID). Method request() saves read requests in a queue for reader requests and write requests in a queue for writer requests. The request queues are used in methods startRead() and startWrite() to force reader and writer threads to read and write in the correct order. For
252 |
MONITORS |
example, method startWrite(int ID) might contain an if-statement such as |
|
the following: |
|
if (writing || |
// writer writing |
readerCount>0 || |
// reader(s) reading |
earlierReadersHavePriority || |
// readers temporarily |
|
// have priority |
ID != ((request)writeRequests.getFirst()).ID |
// ID not first in the |
|
// write request queue |
) |
|
waitingWriters[ID].waitC(); |
// wait on the condition |
|
// variable used by thread ID |
4.13.Section 3.5.4.2 showed a semaphore implementation of strategy R>W.2. This strategy allows concurrent reading and generally gives readers a higher priority than writers. Writers have priority in the following case: When a reader requests to read, if it is a “lead reader” (i.e., no other reader is reading or waiting), it waits until all writers that arrived earlier have finished writing. Below is an SU monitor implementation of this strategy.
(a)Is this monitor solution equivalent to the semaphore-based solution in Section 3.5? Explain.
(b)If they are not equivalent, show how to modify the monitor solution to make it equivalent to the semaphore solution.
int readers = 0; /* number of readers */ boolean writing = false; conditionVariable writers_readers_que; conditionVariable readers_que;
public void startRead() { if (writing)
if (readers == 0) writers_readers_que.wait();
else readers_que.wait(); readers++;
}
public void endRead() { --readers;
if (readers == 0) writers_readers_que.signal();
}
public void startWrite() {
if (writing || readers > 0) writers_readers_que.wait(); writing = true;
}
EXERCISES |
253 |
public void endWrite() {
writing = false; writers_readers_que.signal();
}
4.14.Write a monitor implementation of an Event object that is similar to the Event object in Win32. Event objects have operations block() and set(). A call to block() always blocks the caller. A call to set() awakens every thread that has called block() since the last time set() was called.
(a)Write implementations of operations block() and set() for an SU monitor. Declare and initialize any variables and condition variables that you use.
(b)Write implementations of operations block() and set() for an SC monitor. Declare and initialize any variables and condition variables that you use.
4.15.Show how to modify classes monitorSC and conditionVariable to produce a monitor with urgent-signal-and-continue (USC) semantics (see Section 4.5.3) such that signaled threads have priority over new threads. In class monitorSC in Section 4.7.1, waiting threads that are signaled wait in the mutex queue with new threads:
public void waitC() { numWaitingThreads++; threadQueue.VP(mutex);
mutex.P(); // enter the mutex queue with new threads.
}
In your new implementation, waiting threads will not join the mutex queue when they are signaled. If threads have been signaled but have not yet reentered the monitor, they should be allowed to reenter before new threads can enter. Threads that execute signalC() are allowed to continue. Check your implementation to make sure that you allow only one thread in the monitor at a time.
4.16.In an SU monitor, the reentry queue is used to keep signaling threads, and each condition variable has a queue to keep waiting threads. Consider the two queuing strategies FIFO (first-in-first-out) and LIFO (last-in-first-out).
(a)Compare the effects of using these strategies for the reentry queue in terms of fairness and correctness.
(b)Compare the effects of using these strategies for the condition queues in terms of fairness and correctness.
4.17.Show how to modify the SC monitor toolbox to create a signal-and-wait (SW) [Howard 1976; Andrews 2000] monitor toolbox. In an SW monitor, a thread calling signalC() joins the rear of the entry queue and the awakened
254 |
MONITORS |
thread enters the monitor immediately. The resulting relative priorities are A(wakened) > S(ignaling) = C(alling).
4.18. Section 4.5.1 shows an SU monitor solution for strategy R>W.1 of the readers and writers problem. Below is a revised version of method startRead.
public void startRead { if (writing) readerQ.wait(); readerQ.signal(); ++readerCount;
}
(a)Assume that the monitor is still of type SU; does the revised solution still implement strategy R>W.1?
(b)Assume that the monitor is of type SW (see Exercise 4.17); does the revised solution still implement strategy R>W.1?
(c)Assume that the monitor is of type SC; does the revised solution implement strategy R>W.1?
Justify your answers.
4.19.The bear and the honeybees (see Exercise 3.13). The bear calls method sleep() to wait for a full honey pot, then method eat() to eat the honey. The bees call method fillPot().
(a)Write implementations of monitor methods eat(), sleep(), and fillPot() as members of an SU monitor using operations wait(), signal(), and signalAndExit().
(b)Write implementations of monitor methods eat(), sleep(), and fillPot() as members of an SC monitor using operations wait(), signal(), and signalAll().
4.20.In Exercise 3.11 you were asked to write a semaphore implementation of method waitB() in class Barrier. Here you are asked to write a monitor implementation. Threads call B.waitB() to wait at Barrier B:
class Barrier extends monitor { public Barrier(int n) {this.n = n;}
private conditionVariable go; // a condition variable for waiting threads public void waitB() { .. }
}
Assume that conditionVariables are FCFS.
(a) Write an SU monitor implementation of method waitB().
