Name ID
Mohamed Abdelrahman Anwar 20011634
Operating Systems
Sheet 6
Concurrency: Mutual Exclusion and
Synchronization
5.4 cont + 5.5 MONITORS
1.
a. For "x is 10", the interleaving producing the required
behavior is easy to find since it requires
only an interleaving at the source language statement
level. The essential fact here is that
the test for the value of x is interleaved with the
increment of x by the other process. Thus, x
was not equal to 10 when the test was performed, but
was equal to 10 by the time the value
of x was read from memory for printing.
Instruction --- x
P1: x = x – 1; 9
P1: x = x + 1; 10
P2: x = x – 1; 9
P1: if(x != 10) 9
P2: x = x + 1; 10
P1: printf("x is %d", x); 10
b. For "x is 8" we need to be more inventive, since we
need to use interleaving of the machine
instructions to find a way for the value of x to be
established as 9 so it can then be evaluated
as 8 in a later cycle. Notice how the first two blocks of
statements correspond to C source
lines, but how later blocks of machine language
statements interleave portions of a source
language statement.
Instruction x P1-R0 P2-R0
P1: LD R0, x 10 10 --
P1: DECR R0 10 9 --
P1: STO R0, x 9 9 --
P2: LD R0, x 999
P2: DECR R0 998
P2: STO R0, x 898
P1: LD R0, x 888
P1: INCR R0 898
P2: LD R0, x 898
P2: INCR R0 899
P2: STO R0, x 999
P2: if(x != 10) printf("x is %d", x) 999
P2: "x is 9" is printed. 999
P1: STO R0, x 999
P1: if(x != 10) printf("x is %d", x); 999
P1: "x is 9" is printed. 999
P1: LD R0, x 999
P1: DECR R0 989
P1: STO R0, x 889
P2: LD R0, x 888
P2: DECR R0 887
P2: STO R0, x 787
P1: LD R0, x 777
P1: INCR R0 787
P1: STO R0, x 887
P1: if(x != 10) printf("x is %d", x); 887
P1: "x is 8" is printed. 887
2. Here the solution is simple: enclose the operations on
the shared variable within semaphore operations, which
will ensure that only one process will operate on x at a
time. The only trick here is to realize that we have to
enclose the if statement as well since if we do not,
erroneous printing can still happen if one process is in
the middle of the critical section while another is testing
x.
s: semaphore;
parbegin
P1: {
shared int x;
x = 10;
while(1) {
semWait(s);
x = x - 1;
x = x + 1;
if (x != 10)
printf("x is %d", x);
semSignal(s);
}
}
P2: {
shared int x;
x = 10;
while(1) {
semWait(s);
x = x - 1;
x = x + 1;
if(x != 10)
printf("x is %d", x);
semSignal(s);
}
}
Parend
3. If a process in a monitor signals and no task is waiting
on the condition variable, the signal is lost. On the other
hand in semaphores, wait operation will catch it because
it just checks the count inside the semaphore.
4. It’s a way to accomplish inter-process communication
that can also be used for
synchronization between processes
We assume the use of the blocking receive primitive and
the nonblocking send primitive. A
set of concurrent processes share a mailbox, box, which
can be used by all processes to send
and receive. The mailbox is initialized to contain a single
message with null content. A
process wishing to enter its critical section first attempts
to receive a message. If the mailbox
is empty, then the process is blocked. Once a process has
acquired the message, it performs
its critical section then places the message back into the
mailbox. Thus, the message
functions as a token that is passed from process to
process.
5. The code for the one-writer and many readers is fine if
we assume that the readers have always priority. The
problem is that the readers can starve the writer(s) since
they may never all leave the critical region, i.e., there is
always at least one reader in the critical region, hence
the ‘wrt’ semaphore may never be signaled to writers
and the writer process does not get access to ‘wrt’
semaphore and writes into the critical region.
6.
monitor buffer;
int readers = 0;
boolean writeLock;
Condition canWrite;
Condition canRead:
void beginRead(){
if(writeLock || queue(canWrite)){
wait(canRead);
}
readers++;
signal(canRead);
}
void endRead(){
readers—-;
if(readers == 0){
signal(canWrite);
}
}
void beginWrite(){
if(readers > 0 || writeLock){
wait (canWrite);
}
writeLock = true;
}
void endWrite(){
writeLock = false; //release lock
if(queue(canRead)){
signal(canRead);
}
else{
signal(canWrite); }
}
7.
a. When a process wishes to enter its critical section, it is
assigned a ticket number. The ticket
number assigned is calculated by adding one to the
largest of the ticket numbers currently
held by the processes waiting to enter their critical
section and the process already in its
critical section. The process with the smallest ticket
number has the highest precedence for
entering its critical section. In case more than one
process receives the same ticket number,
the process with the smallest numerical name enters its
critical section. When a process
exits its critical section, it resets its ticket number to zero.
b. If each process is assigned a unique process number,
then there is a unique, strict ordering of processes at all
times. Therefore, deadlock cannot occur.
c. First: prove the following lemma: if Pi is in its critical
section, and Pk has calculated its number[k] and is
attempting to enter its critical section, then the following
relationship holds:
( number[i], i ) < ( number[k], k )
define the following times:
• Tw1 → Pi reads choosing[k] for the last time, for j = k,
in its first wait, so we have choosing[k] = false at Tw1.
• Tw2 → Pi begins its final execution, for j = k, of the
second while loop. We therefore have Tw1 < Tw2.
• Tk1 → Pk enters the beginning of the repeat loop.
• Tk2 → Pk finishes calculating number[k].
• Tk3 → Pk sets choosing[k] to false.
Its known that: Tk1 < Tk2 < Tk3.
Since at Tw1, choosing[k] = false, we have either
Tw1<Tk1 or Tk3<Tw1. In the first case, we have
number[i] < number[k], since Pi was assigned its number
prior to Pk; this satisfies the condition of the lemma.
In the second case, we have Tk2<Tk3<Tw1<Tw2, and
therefore Tk2<Tw2. This means that at Tw2, Pi has read
the current value of number[k]. Moreover, as Tw2 is the
moment at which the final execution of the second while
for j = k takes place, we have
(number[i], i ) < ( number[k], k), which completes the
proof of the lemma.
It is now easy to show the mutual exclusion is enforced.
Assume that Pi is in its critical section and Pk is
attempting to enter its critical section. Pk will be unable
to enter its critical section, as it will find number[i]≠ 0
and ( number[i], i ) < ( number[k], k ).