You are on page 1of 8

Chapter 11

Process Synchronization

Problem 1: p1 precedes all other processes, p2 precedes all other processes except
 

p1 . p3 p4 and p6 precede processes p5 p7 p8 and p9 , etc. p3 p4 p6 and p8 p9


 

are sets of independent processes. (a) To implement using Fork–Join, use the algo-
rithm given in Section 11.1. (b) Use a Parbegin–Parend for processes p 3 p4 and
p6 , and another for p8 p9 .
Problem 2: A PPG can be implemented using Parbegin–Parend if the following
procedure yields a graph with a single node in it:
1. Find a group of independent processes which have a common predecessor and
common successor. Replace the independent processes, their predecessor and
their successor with a single node. In-edges of the predecessor become in-
edges of the new node and out-edes of the successor become out-edges of the
new node.
2. Repeat Step 1 if applicable.

Problem 3: (a) Apply the procedure of Problem 2. The group of independent pro-


cesses form a nested precedence sequence enclosed in and using the concurrency


operator ‘,’ to separate the processes.


Problem 5: If processes p1 and p2 execute statements c1 : = 0, c2 : = 0 and reach
their while statements at the same time, they will wait for each other to set c 1 /c2 to
1. This is a deadlock situation.
Problem 6: If turn = 2, p1 is trying to enter CS and p2 is not interested in entering
CS, c2 will be 1. Hence p1 enters CS straightaway.
Problem 7: (a) Let a deadlock exist. Hence from p 1 ’s code c1 0 and turn = 2.


From p2 ’s code c2 0 and turn = 1. This is a contradiction. Hence a deadlock




cannot exist. (b) Process p1 defers to p2 by setting c1 to 0. However, on finding


that p2 has also deferred to it by setting c2 to 0, it changes c1 back to 1. That is, it
stops defering to p2 . p2 has analogous behavior. Hence if both processes defer to
2 Solutions Manual: Operating Systems by Dhamdhere

one other, they both stop defering to one another. Now, they both execute their inner
while loops. Hence depending on the value of turn, one of them will enter CS.
Problem 8: Bounded wait condition can be violated only if both processes simulta-
neously show interest in entering CS and one of them enters CS, again gets interested
in entering CS and does so ahead of the other process arbitrarily many times. How-
ever, when both processes wish to enter, the value of turn decides which process
would get in. When this process exits CS, it changes its own flag hence the other
process enters CS irrespective of the value of turn. Hence the bounded wait condi-
tion is satisfied.
Problem 9: This has been discussed in Section 11.2.4.2.
Problem 10: After completing use of CS, a process sets turn to the next process in
modulo order which is interested in entering CS (see the while loop after CS). If no
other process is interested, it encounters its own flag and stops looking for another
process wishing to enter CS. It now sets turn to point at the next process in modulo
order and finishes its iteration of the loop. If it wishes to enter CS once again, it
executes the repeat loop in which it checks if any other process wishes to enter CS.
If not, it enters CS.
Problem 11: Processes enter CS in the order of their token numbers. The second
while loop ensures this. If some process p j is currently choosing a token can another
process pi assume that pj ’s token would be larger? This is not so, because p j may
have started choosing a token before p i , but after choosing the token it may have
been preempted before it could set choosing[ j] to false. If p i now chooses a token,
it would get a token larger than pj ’s. In this case, even though pj appears to be still
choosing a token when pi executes the second while loop, it actually has a token
smaller than pi ’s! To avoid this situation, pi would wait for pj to finish choosing and
then compare pj ’s token with its own to decide if it can enter CS.
Problem 12: In this solution, an actual produce or consume action takes place inside
a CS. This feature permits only one produce or consume action to be in progress.
When many producers and consumers exist this feature can be changed through the
following provisions: (1) Each producer uses its own local flag p found. (2) A pro-
ducer first produces a record in a temporary area and then enter the while loop to find
an empty buffer. When it finds one, it puts the produced record into the buffer. Anal-
ogous provisions are made in a consumer. This way produce and consume actions
take place outside CS. This arrangement permits many producers and consumers to
access buffers simultaneously.
Problem 13: Counters full and empty should be manipulated inside critical sections
using mutexes. This immediately gives rise to the busy wait problem—what should
a producer do if it finds empty = 0?. We should block such a producer using a P
operation on a semaphore Produce. A consumer would perform a V operation on
produce under the correct conditions. A semaphore Consume would be used for
Process Synchronization 3

similar purposes.
If many producer and consumer processes exist, the buffer pointers prod ptr and
cons ptr would also have to be protected by enclosing in a CS. (It is also best to
perform actual buffer accesses outside CS.) The solution now follows:
const n = ... ;
type item = ... ;
var 

full : integer := 0; Initializations




empty : integer := n;
prod ptr, cons ptr : integer := 0;
buffer : array 0  n  1 of item;
mutex : semaphore := 1;
Produce : semaphore := 1;
Consume : semaphore := 0;
Prodwait, Conswait : boolean := false;
Could produce, Could consume : boolean := false;
Parbegin

repeat repeat
Could produce := false; Could consume := false;
P(mutex); P(mutex);
If empty  0 then if full  0 then
buffer prod ptr := ...;

X := buffer cons ptr ;


i.e. produce

i.e. consume 

prod ptr := prod ptr  1 mod n; cons ptr := cons ptr  1 mod n;
empty := empty  1; empty := empty  1;
full := full  1; full := full  1;
Could produce := true; Could consume := true;
if Conswait = true then if Prodwait = true then
Conswait := false; Prodwait := false;
V(Consume); V(Produce);
else else
Prodwait := true; Conswait := true;
V(mutex); V(mutex);
if Could produce := false then if Could consume := false then
P(Produce); P(Consume);
forever; forever;

Parend

Producer Consumer
4 Solutions Manual: Operating Systems by Dhamdhere

Problem 14: Two changes are needed to provide writer priority: (1) A reader enters
if no writer is writing. This is to be changed such that a reader enters only when no
writer is writing or waiting. Hence the first if statement should be changed to use the
condition totwrite = 0. (2) After finishing a write operation, the writer should check
if a writer is waiting to write. If so, it must activate the writer. Else it must activate
waiting readers, if any. For this purpose, the while and the second if statements
should be interchanged—in fact, the while should be put in the else clause of the if.
The if statement need not check for runread = 0, it should simply check if totwrite 
runwrite.
Problem 15: Let a writer be writing when a reader arrives. The reader will perform
a P(reading) inside the CS on mutex, and get blocked. When the writer finishes, it
will perform a P(mutex) in order to update relevant counters and decide whether to
activate a writer or reader(s). However, it will be blocked on the P operation since a
reader is inside the CS. Now we have a deadlock situation.
Problem 16: (a) No, because the semantics of a V operation do not specify which
process should be activated if several processes are waiting. (b) No. (c) No.
Problem 17: The key point is implementation of FIFO behavior. (a) It is best
to declare an array of semaphores and let each process use a semaphore for self-
scheduling. The request resource procedure would either perform a V operation on
the scheduling semaphore of the requester or put the requester id in an array of pend-
ing requests. The release operation would enable one of the waiting requesters by
performing a V on the appropriate semaphore picked up from the array of pending
requests.
(b) A similar scheme can be used with conditional critical regions, the only differ-
ence being use of an await condition on a scheduling flag called proceed[i] for each
process pi . The flag would be manipulated by the request and release procedures.
These procedures would also manipulate the array of pending requests.
Problem 18: The changes are analogous to those in Problem 14. Introduce a count
totwrite and statements to increment and decrement its value. A reader should be
allowed to read only if totwrite = 0. A writer should wait on the condition (run read
= 0 and run write = 0). However the condition run write = 0 is redundant because it
is used in the CCR on variable read write; it is trivially true when any writer evaluates
it. After performing a write, a writer should enable a waiting writer, if present. If
not, it should enable waiting readers, if any.
Problem 19: Deadlocks do not arise if some philosopher is able to pick both left and
right forks. (a) At least one seat will be vacant. Let the vacant seat be to the right of
some philosopher. If the philosopher is be able to lift the left fork without difficulty,
then he/she will be able to lift the right fork as well, eat and put down both forks. If
he/she cannot lift the left fork, his/her left neighbor would have lifted the right fork.
He/she can use the fork after his/her left neighbor finishes eating and puts down the
Process Synchronization 5

fork. Since a seat is vacant, some philosopher will be able to lift the left fork. This
avoids deadlocks. (b) Yes. Presumably a left-handed philosopher first picks up the
right fork and then the left fork. This again ensures the absence of a deadlock.
Problem 20: (a) Deadlocks can be prevented by lifting both forks simultaneously.
The condition in await statements can take care of this. However, this solution would
permit only one philosopher to lift the forks at any time. Several philosophers would
not be able to do it simultaneously. This problem can be alleviated by making each
philosopher process do the eating outsider the CCR.
(b) It is not easy to implement lifting of both forks simultaneously. We can use
resource ordering to prevent deadlocks. Let all forks be numbered in an anticlock-
wise direction. Now for most philosophers the left fork has a smaller number than
the right fork. Only one philosopher has a smaller numbered right fork. Let each
philosopher know the numbers of his/her left and right fork and ask for them in as-
cending order by number. Each fork can be implemented as a condition variable.
Following Problem 19, Part (b), no deadlocks can arise.
Problem 21: This is an instance of bounded concurrency. A semaphore initialized
to 5 can be used to implement it. The interesting part is how does a process know
which printer to use? Printer id’s can be kept in an array. When the request procedure
gets past a P operation, it deletes the first id from the array and passes it to the user
process. The user process uses the printer and passes its id in the call on the release
procedure.
Problem 22: (a) The reservations data would become data of the monitor. Book-
ings and Cancellations would be monitor procedures. (b) Very little synchronization
would be necessary. In fact, mutual exclusion of the monitor is all that is needed.
Use of CR or CCR would have yielded a similar implementation.
Problem 23: The monitor should have another variable to hold the value n, a con-
dition variable try debit and a data structure to hold pending debits. Procedure debit
should enter an infeasible debit in the pending debits structure and execute a state-
ment try debit.wait if this is the first debit entry in the structure. Effectively, sub-
sequent infeasible debits are entered in the pending debits structure but a wait is
not executed. Following this statement it should try to perform as many debits from
the pending debits structure as possible. Procedure credit should ignore a credit if
balance  n. After performing a credit, it should execute try debit.signal.
Problem 24: We have two kinds of processes—a single barber process and several
customer processes. A deadlock arises if the barber goes to sleep and customers
expect him to wake up and admit a customer, whereas the barber expects a customer
to wake him. The barber process uses 3 procedures: Check and admit customer,
finish customer and sleep. A customer process uses 2 procedures: check and wake-
barber and wait. A monitor can be defined to contain these procedures and relevant
data. Monitor procedures must use wait and signal to implement the necessary syn-
6 Solutions Manual: Operating Systems by Dhamdhere

chronization.
This is a very interesting problem. However, many of the complications vanish
when a monitor is used. In fact, implementation of the above outline can be almost
uneventful!
Problem 25: This is a very interesting and important exercise for practice in con-
current programming. In fact, when I offer an undergraduate course in OS, I always
give this exercise as a laboratory assignment. It brings out many interesting points
concerning concurrency and deadlock possibilities.
The monitor for the interprocess communication system (minus the deadlock
detection feature) is as follows :
Monitor
type
msg ptr = msg;
txt = array 1  200 of character;
msg = record
text : txt;
destination : integer;
ptr : msg ptr;
end;
var
message pool : array 1  20 of msg;
free list : msg ptr;
wake up : array 1  4 of condition;
no space : condition;
in messages : array 1  4 of msg ptr;

Procedure entry send (msg txt : txt; destination : integer);


begin
if free list = null then no space.await;
else 


Delink a message unit from free list 

Enter details in message unit





Link the message unit to the list starting on


in messages[destination] 

wake up destination .signal;


end;
Procedure entry receive (msg area : txt; proc id : integer);
begin
if in messages dest = null then wake up proc id .await;
else 

Copy message from the message unit pointed by


in messages[proc id]

Process Synchronization 7


Delink the message unit from list starting on


in messages[proc id]



Link the message unit to free list 

no space.signal;
end;
begin 


Link all elements in message pool to free list 

Set all elements of in messages array to null

end.

Problem 26: Structurally this monitor is analogous to the Bank monitor of Problem
23. A request is entered in a requests data structure in a sorted order according to
time. The earliest time is entered in a variable called next event at. The procedure
handling the elapsed time signal updates the time and compares it with next event at.
It wakes a request handling procedure if the next event time has occurred.
Problem 27: A consumer waits on buff full only if full is 0. Hence a producer needs
to performs buff full.signal after incrementing full only if new value of full is 1.
Similarly, a consumer should perform buff empty.signal only if the new value of full
is n  1.
Problem 28: Let process pi invoke a procedure of monitor A. While this procedure
is in execution pi holds mutual exclusion over A. Let this procedure call a procedure
of monitor B and get blocked on entry to B because some procedure of B invoked by
some process pj is active. Effectively pi holds mutual exclusion over A and needs
mutual exclusion over B. Let B’s procedure invoked by p j call a procedure of monitor
A. It would be blocked on entry to A. Effectively p j holds mutual exclusion over B
and and needs mutual exclusion over A. This is a deadlock situation.
Problem 29: (a) Mutual exclusion over a monitor can be implemented using a binary
semaphore. P and V operations would be performed when a monitor procedure is
invoked and finishes its execution, respectively. (b) Monitor procedures are executed
in a mutually exclusive manner, so why should they be re-entrant? The reason is that
execution of a procedure would be suspended if it executes a wait statement. Some
other process may now call it and commence its execution. Hence each monitor
procedure should be reentrant. See Section 5.6.6 for details.
Problem 30: Rules for this readers–readers system are fairly obvious: Readers can
concurrently read one part of data, however no reader can read another part of data
at the same time. When the last reader finishes reading one part of data, all readers
wishing to read the other part must be enabled.
The simplest way to implement this readers–readers system is have the notion
of the ‘current’ part of data. Any reader wishing to read it can commence reading
straightaway. Other readers have to wait. When the last reader exits from one part
8 Solutions Manual: Operating Systems by Dhamdhere

of data, the other part of data can become the ‘current’ part. All blocked readers
wishing to read it will be activated now. When no readers are active, an arriving
reader can commence reading straightaway. The ‘current’ part of data should be set
to the data it wishes to access. One can adapt a solution of the 2-process CS problem
from Section 11.2 for this purpose. However, it is simplest to use a monitor with a
single procedure for reading. This procedure will perform both wait and signal on a
condition variable! (Note that all readers waiting for a part of data must be activated
so that they read the data concurrently.)
Problem 31: Let the bridge be East–West. A procedure can control entry to the
bridge from East, and another procedure can control entry from West. Similarly two
procedures control exit at the West and East ends of the bridge. Procedures for entry
from East and exit at West cooperate to maintain counts of vehicles waiting to enter,
and vehicles traveling in the East–West direction. Similar arrangement exists for the
West–East direction. Procedures for entry to the bridge check all this data and decide
whether a new vehicle can start crossing the bridge.
Problem 32: An additional counter to count how many vehicles have started crossing
the bridge in the current phase would be needed. Rules for its use are obvious.

You might also like