ICS412 - Fall 2009 - Homework #3 -
Work alone
You are expected to do your own work on all homework assignments. You may
(and are encouraged to) engage in general discussions with your
classmates regarding the assignments, but specific details of a solution,
including the solution itself, must always be your own work. (See
the statement of Academic Dishonesty on the course's syllabus.)
What to turn in?
You can turn your answers on paper on the day the assignment is due (during
class or in my office). Alternately you can turn in an electronic copy via
e-mail to henric@hawaii.edu and to altunkay@hawaii.edu with a
subject line like "ICS412: HW#3" before 11:59PM on the day the assignment
is due.
Exercise #1 (2pts):
Explain why a spin-lock is not a good idea on a single processor, single
machine.
Exercise #2 (8pts):
Condition variable implementations typically provide a signal_all()
function to wake up all threads blocked on the condition variable. (In Pthreads it's pthread_cond_broadcast().) Consider the following code
fragments for the Bounded Buffer Producer Consumer problem, for an arbitrary number of producers and consumers, written in OO Pseudo-Code. mutex and cond are a lock and a condition variable, respectively, both defined elsewhere in the code and visible by producers and consumers.
Producer:
...
mutex.lock();
while(buffer.isFull())
cond.wait(mutex);
buffer.insert();
cond.signal_all();
mutex.unlock();
...
Consumer:
...
mutex.lock();
while(buffer.isEmpty())
cond.wait(mutex);
buffer.remove();
cond.signal_all();
mutex.unlock();
...
Explain why if the calls to signal_all() were replaced by calls to
signal() the code would not behave properly. What would be the problem? Give a concrete sequence of events for which this code would misbehave. Assume that condition variables are FIFO: upon a call to signal() the thread that had placed the first call to wait() is awakened.
Hint: It's possible to find a simple bad sequence of events for
a buffer with one slot and for two producers and two consumers.
Exercise #3 (12pts):
We consider a program in which we have two kinds of threads.
Adder threads ad 1 to a shared counter. Subtracter threads
subtract N from the shared counter (where N is an integer > 0).
There can be an arbitrary numbers of Adders and Subtracters arrivals (possibly a finite number of them). The counter is set to zero initially. Here are the
code's requirements:
- The counter should never be negative.
- The counter should never stay at a value ≥ N as long as there is
a subtracter in the system.
- Subtracters need to block until they can safely
do the subtraction (i.e., without making the counter negative).
Consider the following implementation based on Semaphores:
Three Semaphores with initial values:
- mutex_counter: 1
- mutex_sub: 1
- notZero: 0
Adder:
. . .
L1 P(mutex_counter);
L2 counter++;
L3 V(mutex_counter);
L4 V(notZero);
. . .
Subtracter:
. . .
L5 P(mutex_sub);
L6 for (i=0; i < N; i++)
L7 P(notZero);
L8 V(mutex_sub);
L9 P(mutex_counter);
L10 counter -= N;
L11 V(mutex_counter);
. . .
Question #1 (2pts): Would there be a problem if semaphore mutex_counter where used instead of semaphore mutex_sub in lines L5 and L8? If so, which one? If not, why?
Question #2 (2pts): Would there be a problem if lines L8 and L9 were switched around? If so, which one? If not, why?
Question #3 (2pts): Would there be a problem if lines L3 and L4 were switched? If so, which one? If not, why?
Question #4 (6pts): Using the same style of pseudo-code as in Exercise #2, write an equivalent
implementation using one lock and one condition variable, and no semaphores.
henric@hawaii.edu