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:
(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.
[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.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
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. 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.
_________________________________________________
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.
_________________________________________________
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.
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.
_________________________________________________
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);
}
_________________________________________________
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