CS 620

Solution for Assignment 8

1. (10 points)

The following is a variation of the critical section codes described in class. (Initially, flag[0] and flag[1] are both false.)

          THREAD 0                                    THREAD 1
          for(;;)                                     for(;;)
          {                                           {
          ...                                         ...
          flag[0]=true;                                 while (flag[0]==true);
          while (flag[1] == true);                      flag[1]=true;
            <critical section>                            <critical section>
          flag[0]=false;                                flag[1]=false;
            <non-critical section>                        <non-critical section>
          ...                                         ...
          }                                           }
(Notice that the codes for the two threads are asymmetric.) For the questions given below, justify your answer completely. Regarding this code:

[a]. Is mutual exclusion of the critical section guaranteed?
[b]. Can Thread 0 starve out Thread 1?
[c]. Can Thread 1 starve out Thread 0?
[d]. Is deadlock possible?
[e]. If a thread dies in its <non-critical section>, can it block the other thread?

[Answer]
[a.] No. Here is a counter example:
Suppose THREAD 1 is executed first:
    (Initially flag[0] = flag[1] = false;)
    THREAD1: (1) while (flag[0]==true);
             (context switch;)
    THREAD0: (a) flag[0] = true;
             (b) while (flag[1] == true);
             (c) <critical section>
             (context switch;)
    THREAD1: (2) flag[1] = true;
             (3) <critical section>

   Now both thread 0 and thread 1 are in critical section, so mutual exclusion is not preserved.
[b.] Yes. Here is one case: Thread 0 can executes (a),then Thread 1 executes (1) and stay in (1). Then thread 0 executes (b), (c), (d) and (e) then go back to (a) and set flag[0] again, then Thead 1 stays in (1) again. So Thread 1 would starve if this procedure repeats.

[c.] No. Because Thread 1 always tests if flag[0] is true before it does anything else. Once Thread 0 set flag[0] to be true, Thread 1 has to wait until Thread 0 finishes critical section and sets flag[0] back to false.

[d.] No. Thread 0 sets flag[0] first before it tests flag[1] while Thread 1 always tests flag[0] first before 
     it sets flag[1]. This means Thread 0 can always enter the critical section because:
if (a) then (1), then Thread 1 has to wait and Thread 0 can enter the critical section;
if (1) then (a), then Thread 0 and Thread 1 can both enter critical section;
if (1), (2) and (a), then Thread 1 enters the critical section and Thread 0 waits, but Thread 1 will exit the critical section and sets flag[1] to false and then Thread 0 enters the critical section.
Therefor the deadlock is not possible.

[e.] No. Because the flags have been set back to false in either thread before it dies in its non-critical section so the other thread can go into the critical section.


_________________________________________________

2.(12 points)

r1 = 5 + a;
r2 = r1 - b;
r3 = e + f;
r4 = c * d;
r5 = r1 + r2;
r6 = r4 * r5;
r7 = 4 - r3;
r8 = r4 * r6;
answer = r8; 

In the above computation, the lower-case letters refer to memory variables. Assume that each of the above steps takes 1 time unit to complete. Hence, the entire computation will take 12 time units on a single CPU.
Suppose you were running this code on a 2 processor machine and you decide to split the above code into 2 threads that can be run in parallel on the 2 processors. For example, r1 = 10 / a; and r3 = e + f; can be executed in parallel since these 2 commands do not affect each other.
The goal is to execute the above code in the least possible time on 2 processors. The threads on the 2 CPUs need to be synchronized. For example, if Thread1 contains the code r4 = c * d; and Thread2 contains the code r8 = 1 / r4, you must ensure that r8=1 /r4 executes after r4=c * d.

Use semaphores to synchronize the execution of the code on 2 processors. Assume that the P() and V() operations take 0 time units to complete (i.e., they are very fast operations compared to the computation time).

[a]. What is the least number of time units required to run the computation on 2 CPUs?
[b].What is the minimum number of semaphore variables required to run the above code on 2 CPUs?
[c].What is the least number of time units required to run the computation on 3 CPUs?
[d].What is the minimum number of semaphore variables required to run the above code on 3 CPUs?

[Answer]

Time     5   a   b   c   d    e   f   4 
          \ /   /     \ /      \ /   /  
  1        r1  /       r4       r3  /
           |\ /       /|         \ /  
  2        | r2     / /          r7
           \ |    /  /  
  3          r5  /  /   
             \  /  /    
  4           r6  /
               \ /
  5             r8
                |
  6           answer
Running computations on 2 PCUs:
                  CPU1                   CPU2
                  ----                   ----
      1:          r1 = 5 + a;            r3 = e + f;
      2:          r2 = r1 - b;           r4 = c * d;
                                         V(s);
      3:          r5 = r1 + r2;          r7 = 4 - r3;
		  P(s);
      4:          r6 = r4 * r5;
      5:          r8 = r4 - r6;  
      6:          answer = r8; 
[a]. The least number of time units: 6

[b]. The minimum number of semaphore variables: 1

-------
Running computations on 3 PCUs:
                  CPU1                   CPU2                    CPU3
                  ----                   ----                    ----
      1:          r1 = 5 + a;            r3 = e + f;             r4 = c * d:
      2:          r2 = r1 - b;           r7 = 4 - r3;            V(s);
      3:          r5 = r1 - r2; 
                  P(s1);                 		
      4:          r6 = r4 * r5;
      5:          r8 = r4 * r6;
      6:          answer = r8;
[c]. The least number of time units: 6.

[d]. The minimum number of semaphore variables: 1.

_________________________________________________

3.(4 points)

What is the meaning of the term busy waiting? What other kinds of waiting are there in an operating system? Can busy waiting be avoided altogether? Explain your answer.

[Answer]
When one process waits to execute its critical section so that other process which is currently in its critical section can finish, then it is called as busy waiting. During this time, the process just loops doing nothing, and hence wasting CPU cycles.
Other kind of waiting in an operating system is when a process executes a blocking system call and gives up the CPU.
Busy waiting cannot be avoided altogether since the wait and busy signals need to be executed atomically.
_________________________________________________

4. (4 points)

Show that if the wait and signal semaphore operations are not executed atomically, then mutual exclusion may be violated.

[Answer]
Consider a situation where one process has executed the wait() operation and context switch occurs which allows the other process to execute its wait() operation and thus both processes can now enter their critical sections at the same time. This would clearly violate mutual exclusion.
Also, if two processes are getting in and 1 process executes the wait() operation and a context switch occurs. Suppose, even before it gets into the wait queue, other process sends a signal (V), then this signal will be lost by the first process.
_________________________________________________

5. (5 points)

Consider the following parallel program:
               Thread x:                        Thread y:                         Thread z:
               for(;;)                          for(;;)                           for(;;)
               {                                {                                 {
                  P(x)                            P(y)                              P(z)
                  P(x)                                                              P(z)
                  P(x)  
                  write "x"                       write "y"                         write "z"
                  V(y)                            V(z)                              V(x)
                  V(y)                            V(x)                              P(z)
                  V(z)
               }                                }                                 }
Initially, x = 5; y = z = 1. Describe the output format of this program.

[Answer]

Suppose each thread gets the same quantum units. The program can start printing from either Thread x or Thread y at the same time, but not from Thread z; after both x and y get print out, x, y and z can all be print out in any order. In the following repeated printing, y gets print most and x gets print least.
_________________________________________________

6. (5 points)

Consider the following synchronization problem: thread UNH adds 7 to a shared variable SCORE; then thread UM and thread BU must both read the value of SCORE (but they are allowed to read SCORE in any order); then after UM and BU read SCORE, thread UNH adds 3 to SCORE and then both BU and UM read the value of SCORE in any order. The entire process repeats. Give the code for these three threads, using semaphores, to guarantee the above sequence of events.

[Answer]

var um_read = 0 : semaphore
    bu_read = 0 : semaphore
    write = 0 : semaphore   

           Thread UNH                Thread UM                Thread BU
           ----------                ---------                ---------
           for(;;)                   for(;;)                  for(;;)
           {                         {                        {
             SCORE += 7;               P(um_read);              P(bu_read);
             V(um_read);               read SCORE;              read SCORE;
             V(bu_read);               V(write);                V(write);
             P(write);               }                         }
             P(write);
             SCORE += 3;
             V(um_read);
             V(bu_read);
             P(write);
             P(write);
           }

_________________________________________________

7. (10 points)

The Sleeping - Barber problem. A barbershop consists of a waiting room with n chairs and a barber room with one barber chair. If there are no customers to be served, the barber goes to sleep. If a customer enters the barbershop and all chairs are occupied, then the customer leaves the shop. If the barber is busy but chairs are available, then the customer sits in one of the free chairs. If the barber is asleep, the customer wakes up the barber. Write a program (pseudo code) to coordinate the barber and the customers.

[Answer]

var avail_seats = n : semaphore
    wake_up_barber = 0: semaphore
    barber_available = 1: semaphore

customer:

for(;;)
{
   if(avail_seats == 0){ // no seats available, waiting room completely filled

     exit; // customer leaves
   }
   else{  // at least one seat available ( room may be empty/ filled)
      P(avail_seats) // decrement the number of available seats
   }
   if(avail_seats == n-1){  // room was completely empty, this is the only customer
     V(wake_up_barber); 
   }
   else{
     P(barber_available);
     V(wake_up_barber);
   }
   V(avail_seats); // increment the  number of available seats
}


barber: for(;;) { P(wake_up_barber); // cut hair V(barber_available); }
_________________________________________________

Return to the CS 620 Home Page