CS 414 Fall 1997: Homework 2 (due Sept. 23)

 

 

 

Recall the code for the producer in the bounded-buffer problem.  That code looked like the following:

Produce(x: obj):   (1)

{ (2)

(* Code to put x into the buffer *) (3)

WAIT(nfree); (4)

WAIT(mutex); (5)

Buffer[pptr] := x; (6)

pptr := (pptr+1) mod B; (7)

SIGNAL(mutex); (8)

SIGNAL(ninuse); (9)

} (10)

Consume(): obj                                                              (11)

{ (12)

(* Code to extract one item from the buffer *)(13)

WAIT(ninuse); (14)

WAIT(mutex); (15)

consume := Buffer[cptr]; (16)

cptr := (cptr+1) mod B; (17)

SIGNAL(mutex); (18)

SIGNAL(nfree); (19)

}

 

1)      Suppose that the SIGNAL(inuse) was moved inside the WAIT(mutex)…SIGNAL(mutex) by swapping lines (8) and (9), and the SIGNAL(nfree) was similarly moved inside the mutex by swapping lines (17) and (18). Would this change the execution of the code in an important way?  Explain. 

This change would have no effect at all.  To get past lines (5) and (15), a process must first do a WAIT() on both semaphores – nfree and mutex, or inuse and mutex. SIGNAL never blocks the caller, so the order of doing the SIGNAL() operations is unimportant.

2)      Suppose that the WAIT(mutex)…. SIGNAL(mutex) were moved to the outside of the whole block of code, e.g. lines (4) and (14) would now both be WAIT(mutex) and lines (9) and (19) would be SIGNAL(mutex).  Would this change the execution of the code in an important way?  Explain.

This would cause the code to hang (it wouldn’t be live).  Now you could have some process that does a WAIT(mutex) and gets the mutex, but then waits by doing a WAIT(inuse) or a WAIT(nfree) when those semaphores are 0.  No other process could get into the critical section, even to do the SIGNAL() operation, thus leaving the modified solution “stuck” forever.

3)      Suppose that we broke up the producer’s critical section by adding an extra SIGNAL(mutex); WAIT(mutex) in between lines (6) and (7) (but that we leave the consumer unchanged).   So the new producer would have this code in it:

WAIT(mutex); (5)

Buffer[pptr] := x; (6)

                                    SIGNAL(mutex);                                            (xx – new line)

                                    WAIT(mutex);                                                (xx – new line)

pptr := (pptr+1) mod B; (7)

SIGNAL(mutex); (8)

     Assume that objects are “characters”, that the buffer is initially all zeros, and that there are initially 6 producer threads which produce characters ‘a’, … ‘f’ respectively.  Assume that these threads begin execution concurrently and hence can invoke produce in an arbitrary order.  Now, assume that there is a single consumer thread and it prints the characters it obtains from the buffer.  For each of the following, explain why the output shown cannot occur, or give a sequence of events that would cause it to be printed.   Also tell us if the output could also occur with the original, correct code, or can only occur with the new, buggy code.

(a)    The output is ‘abcdef’

This can occur with the original code and can still occur with the new code.  It happens if the producers enter one by one in the order shown, or enter concurrently but happen to get the mutex in the order shown.

(b)   The output is ‘fedcba’

This can occur with the original code and can still occur with the new code.  It happens if the producers enter one by one in the order shown, or enter concurrently but happen to get the mutex in the order shown.

(c)    The output is  ‘a\000\000\000\000\000’

This can occur as a result of the code change – it is a form of bug that the change introduces.  Suppose that all six producers enter concurrently and all six execute line (6) before any of them gets to line 7. The characters all get stored at location 0 of the buffer, and the last one stored is the only one you’ll end up seeing (‘a’ in this case).  Now all six will SIGNAL(ninuse) the consumer will try and consume six characters.  It sees the last value written in buffer(0) and five 0’s, because the initial value was 0 (I assume that 0 prints as \000, which is what happens in most computer systems these days).

(d)   The output is ‘\000\000\000\000\000a’

This output cannot occur.  Even with the change to the code, the first buffer element would have had one of the legal character values in it.

(e)    The output is ‘abacad’

This cannot occur.  If ‘a’ is only produced once, and the consumer moves `cptr’ one step at a time through the buffer, the consumer will only see one ‘a’ in the buffer and hence will only print ‘a’ once, if at all.

(f)     The output is ‘d’ (just one character, not six as for the examples above)

This can’t occur either.  If the producers all produce a value, a scheduler must eventually let them in, and eventually they will call SIGNAL(inuse) 6 times, and eventually the consumer will manage to consume six values.

 

4)      Suppose that each process models a student living in a co-ed dorm with a single shared shower room (with lots of shower stalls in it).  A process looks like this:

Pi:                while(true)

                   {

                        non-critical code

                        Enter the shower room

                                    Use the shower room

                        Leave the shower room

            }

 

     Assume that processes 0…M-1 are male and that processes M…M+N-1 are female, and that M and N are both non-zero.  Use fair general semaphores to implement a unisex shower room policy. 

 

The following code is a modified readers/writers solution.

 

var nm, nw, wm, wf: Integer := {0,0,0,0}

var mwait, wwait, mutex: Semaphore := {0,0,1};

 

MEnter:

            P(mutex);

            if(nw > 0 or ww > 0) { wm := wm+1; V(mutex); P(mwait); }

            else { nm :=nm+1; V(mutex); }

MLeave:

            P(mutex);

            nm := nm-1;

            if(nm = 0 and ww > 0) {

                        while(ww>0) { ww := ww-1; nw := nw+1; V(wwait);             }

            }

            V(mutex);

WEnter:

P(mutex);

            if(nm > 0 or wm > 0) { ww := ww+1; V(mutex); P(wwait); }

            else { nw :=nw+1; V(mutex); }

WLeave:

            P(mutex);

            nw := nw-1;

            if(nw = 0 and wm > 0) {

while(wm>0) { wm := wm-1; nm := nm+1; V(mwait); }

            }

            V(mutex);

 

 

5)       In the Dining Philosopher’s problem, assume that we know that there are 5 philosophers and we also know that philosopher 3 is never hungry while philosopher 4 is hungry (or eating).  Thus one or the other might be hungry or eating, but both would never be doing this at the same time.  Would deadlock be an issue in this case?  Explain.

 

Deadlock cannot arise in the Dining Philosopher’s problem if we have some way to be sure that the philosophers won’t all try to eat at the same time.  With this knowledge, we can rule out any possibility of a cyclic wait – and we know that a cycle is a necessary condition for deadlock.