CS 481: Solution to Assignment #3

  • Problem 23. Use send/receive message passing primitives to implement a semaphore.

    The basic idea is to let each semaphore be implemented by one or more processes and turn the P, V operations of the user process into message exchanges between the semaphore process(es) and the user process. The simplest implementation is one in which a P operation becomes a sequence of two message operations: first send a request message to the semaphore process, then wait for a (favorable) reply; a V operation becomes a simple message sending (announcing release of the resource). The semaphore process has an infinite loop in which it waits for a message, decide which type of message was received (a request or a release), updates its internal variable(s) as appropriate, and, if the resource is available and there is a pending request, sends a message back to the requester.

    The only problem left is identifying the process corresponding to the semaphore (or creating the process in the first place), since a sempahore name is now really a process ID. We can postulate a number of reasonable mechanisms, some centralized (a single process which is known to all and which keeps track of all semaphore processes and so acts as a go-between, with the advantage that new semaphores can be created at any time) and some distributed (but mostly relying on having every semaphore named in the code).

  • Problem 28. Starvation and deadlock are closely related; often, solving starvation leads to potential deadlocks and avoiding deadlocks can create starvation. Give an example of each situation.

    Our example of the dining philosophers gives us an example of each. If we try to avoid a deadlock by denying partial allocation (i.e., by forbidding a philosopher to pick up just one fork), we can easily set up a starvation situation where philosophers i-1 and i+1 can starve philosopher i (by design or accident) by alternating their eating times with some overlap always present. If we decrease the potential for starvation by allowing philosopher i to stake a claim before one of his neighbors by allowing him to grab just one fork, we introduce the possibility of each philosopher grabbing just one right fork, with consequent deadlock. In general, a strategy against starvation is partial allocation, since partial allocation prevents other processes from passing ahead (they would lack the resources to do so); but partial allocation is one of the four key conditions for deadlocks. Conversely, denying partial allocation sets the stage for starvation: a process that needs to acquire several resources at once may easily starve because other processes that need fewer resources keep passing ahead, using up some of the needed resources.

  • Problem 29. Use binary semaphores to implement a counting semaphore.

    The basic idea is to use three pieces for each counting semaphore: a counter, a binary semaphore to protect the counter, and a second binary semaphore to queue up processes that need to be blocked. For the new counting sempahore count, we use a binary semaphore count_mutex (initialized to true) to ensure exclusive access to the value of the counter and another binary sempahore count_sleep (initialized to false) to put processes to sleep.

    P(count)
    1: P(count_mutex)
       count--
       if count < 0
          then V(count_mutex)
               P(count_sleep
               go to 1
          else V(count_mutex)
    

    V(count)
       P(count_mutex)
       count++
       if count <= 0
          then V(count_mutex)
               V(count_sleep)
          else V(count_mutex)
    
  • Back to CS 481 home page