0% found this document useful (0 votes)
76 views8 pages

Exercises On Sychronization2023 Solutions

Uploaded by

Huy Đặng
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
76 views8 pages

Exercises On Sychronization2023 Solutions

Uploaded by

Huy Đặng
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

Solutions to exercises on synchronization 2024

1. What happens in the following pseudocode if

Process 1 Process 2
for ( ; ; ) { for ( ; ; ) {
wait(S); wait(Q);
print(a); print(b);
signal(Q); signal(S);
} }

(a) the semaphores S and Q are both initially 1?


Sol: Either process might execute its wait statement first. The
semaphores ensure that a given process is no more than one iter-
ation ahead of the other.
(b) the semaphores S and Q are both initially 0?
Sol: If both semaphores are initially 0, a deadlock occurs.
(c) one semaphore is initialized to 0 and the other one to 1?
Sol: If one semaphore is initially 1 and the other 0, the processes
proceed in strict alternation.

2. The pseudocode below illustrates the basic push() and pop() operations
of an array-based stack. Assuming that this algorithm is used in a
concurrent environment, answer the following questions:

(a) Which data have a race condition? sol: problem with the top
variable
(b) How could the race condition be fixed? Sol. By making the update
of this variable a critical section. The code line of top + + should
be proceeded by a synchronization such as wait(mutex) followed
by signal(mutex) where mutex is a binary semaphore initialized
to 1. Similarly with top − − using the same mutex semaphore.

push(item) {
if (top < SIZE) {
stack[top] = item;
top++;
}
else ERROR
}

pop() {
if (!empty()) {
top = top - 1;
return stack[top];
}
else ERROR
}
is empty() {
if (top == 0) return true;
else return false;
}

3. A process B must do an operation opB() only after a process A has


done operation opA(). How can you guarantee this using semaphores?
sol:
opA(); signal();
opB(); wait();

4. Consider the following 3 processes that run concurrently

P1 P2 P3
print(Y) print(O) print(U)
print(ARE) print(OK) print(NOW)

Use semaphores and semaphore initializations such that the result printed
is YOU ARE OK NOW
SoL: s1 = 0; s2 = 0; s3 = 0

P1 P2 P3
wait(s2) wait(s3)
print(Y) print(O) print(U)
signal(s2) signal(s3) signal(s1)
wait(s1) wait(s2) wait(s3)
print(ARE) print(OK) print(NOW)
signal(s2) signal(s3)

5. Consider the following 3 processes that run concurrently

P1 P2 P3
OP1 OP2 OP3

You want the processes to have the following behaviors: Process P3


must execute its operation OP3 before any of the two other processes.
Then processes P1 and P2 may execute their operation in any order.
Use semaphores to impose this behavior, don’t forget to provide the
initial values of the semaphores
Sol: need 1 semaphore s initialized to 0. P1 and P2 block on this
semaphore. Once P3 has completed, it signals the value of the semaphore.
Each process P1 and P2 must be followed by a signal(s) so to give the
opportunity to the other process to execute.

P1 P2 P3
wait(s) wait(s) OP3
signal(s)
OP1 OP2
signal(s) signal(s)

6. Consider the following two processes that run concurrently and where
initially y = z = 0

P1 P2
int x; y = 1;
x = y + z; z = 2;

(a) What are the possible final values for x? Sol. 0, 1, 2 and 3. x = 2
when P1 is de-scheduled after copying y = 0, then P2 is run, it
changes the value of y and z, then P1 run again, copy z = 2, then
x = (y = 0) + (z = 2).
(b) Is it possible, using semaphore, to have only two values for x? If
so, list the two values and explain how you can get them. Sol:
From the semantic of the code, either y+z is performed with the
initial value of the variables or after they have been modified by
process P2 . Using semaphores we can select either way by having
process P2 blocked so that P1 executes first, thus x = 0 or block
process P1 until process P2 has executed, then x = 3.

7. Consider the following two processes that run concurrently

P1 P2
print(A); print(E);
print(B); print(F);
print(C); print(G);

Insert semaphores to satisfy the following properties. Don’t forget to


provide the initial values of the semaphores

(a) Print A before F


(b) Print F before C
Sol: We can use two binary semaphores s1 and s2 initialized to 0

P1 P2
print(A); print(E);
signal(s1 );
wait(s1 );
print(B); print(F);
signal(s2 );
wait(s2 );
print(C); print(G);

8. Consider the following two threads:


T1 = while true print Y
T2 = while true print Z
Add semaphores such that at any moment the number of Y or Z differs
by at most 1. The solution should allow strings such as: YZZYYZZYZY
Sol: Need two binary semaphores s1 and s2 initialized to 1
T1 = while true wait(s1 ); print Y; signal(s2 );
T2 = while true wait(s2 ); print Z; signal(s1 );
9. Consider the following two processes P1 and P2 that run concurrently
and share the variables y, z, which are initialized as y = z = 1. What
are the possible final values of x once the two processes have completed?

P1 P2
int x; y = 2;
x = y + z; z = 3;

sol: 2, 3, 4, 5
10. The semantic of locks is as following

acquire(lock)
critical section
release(lock)

Assume a computer system that has only one CPU. Can the lock be
implemented as following, explain why or why not.

void acquire(lock) {
diseable interrupts;
}
void release (lock) {
enable interrupts;
}
sol: Let T1 be a thread executing code in a critical section after ob-
taining a lock. The thread T1 can still be de-scheduled. For example,
the quantum time of T1 expires before T1 complete the execution of the
code in the critical section. If the instruction disable interrupts above
was executed after acquiring the lock, it will prevent the de-scheduling
of thread T1 as most of the interrupts will be blocked, particularly inter-
rupts issued by the hardware timer that signal the end of a quantum
time. So yes it can be implemented this way. However only kernel
threads can disable interrupts, this instruction cannot be called by a
user thread. OS kernels constantly disable interrupts as a synchroniza-
tion mechanism while executing kernel threads.

11. In the Bounded Buffer problem we discussed in class, there is a buffer


shared by producer and consumer threads. Producer inserts items into
the buffer, and consumer removes items from the buffer. A producer is
blocked if the buffer is full, and a consumer is blocked if the buffer is
empty. Below is a solution with two semaphores, a binary semaphore
mutex = 1 and a counting semaphore empty = n. This solution does
not work. Explain why this solution does not work and give an example
of threads incorrectly accessing the shared buffer.

It cannot block consumers from entering when the buffer is empty. We


could have the first consumer that go through because mutex = 1, then
set mutex = 1 on the exit, thus letting another consumer getting in,
etc. which is wrong as consumers should be blocked when buffer is
empty
We need another semaphore: full. Semaphore full = 0

12. Consider the code below for the readers/writer problem discussed in
the lecture, where multiple threads are executing reader and writer
functions to read/write the shared data base. To prevent that writ-
ers access in same time as readers, the following semaphores are used:
Binary semaphore rw mutex initialized to 1, Binary semaphore mu-
tex initialized to 1, Counting semaphore readers initialized to n, int
read count initialized to 0. Unfortunately the way the semaphores are
used below does not work. Explain what is the problem
sol: The rw mutex should be acquired by the first reader, reader 1. But
because reader 1 release mutex before acquiring rw mutex, there could
be a context switch allowing a second reader, reader 2, to enter the DB.
Since readcount is now equal to 2, the if condition is not executed by
reader 2, it enters the DB. Meanwhile, a writer can catch the rw mutex
before reader 1, the writer will enter the DB while there is a reader in
it.
13. The solution in class to the readers/writer problem can starve the
writer. One solution to this problem will consists to add one semaphore
that both writers and readers threads will have to query. Show how this
solution could be implemented and explain why it solves the starvation
problem for the writers.
sol: Add a new binary semaphore w mutex initialized to 0 and use it as
follow for the writer. For the reader it will start with wait(w mutex);
signal(w mutex);. In this way both readers and writers compete for the
same semaphore. If a writer want to access the DB, and signal(w mutex)
= 0; it will capture the mutex and then any reader will be blocked from
accessing the DB until all the readers in the DB has exited and the
writer has completed its task and release w mutex (signal(w mutex)).

while (true) {
wait(rw_mutex);
wait(w_mutex);
/* writing is performed */
...
signal(rw_mutex);
signal(w_mutex);
}
14. The following C code is a non-atomic implementation of semaphores.
Given the non-atomicity of the semaphores, there exist scenarios where
context switches will cause two threads T1 and T2 that synchronize
with the same semaphore S to enter in a same critical section. Which
one of the scenarios below can cause this situation to occur?

void Wait (Semaphore S) {


while (S.count ≤ 0) {}
S.count = S.count - 1;
}

void Signal (Semaphore S) {


S.count = S.count + 1;
}

(a) Thread T2 calls Signal(S) but then a context switch replaces T2


by T1, this before T2 can write the value S.count + 1 into S.count,
i.e. during the execution of instruction S.count = S.count + 1;
(b) Thread T1 is executing code in the critical section but then a
context switch replaces T1 by T2
(c) Thread T1 calls Wait(S) but then a context switch replaces T1 by
T2, this before T1 can write the value S.count - 1 into S.count,
i.e. during the execution of instruction S.count = S.count - 1;
(d) Thread T1 is looping on the Wait(S) while loop when a context
switch replaces T1 by T2.
(e) None of the above scenarios can occur because threads are not
allowed to context switch while executing code in a critical

sol: It is c, Once pass the while loop, thread T1 is clearly in the critical
section but the value of the semaphore has not been decremented. Thus
T2 can enter the critical section as well.

15. Mutex locks are spinlock (busy waiting) synchronization primitives.


What will happen if a thread T1 context switch while executing a critical
section protected by a mutex lock L0 ?

(a) Nothing special will happen, T1 will resume executing the code in
its critical section once it is re-scheduled
(b) The system can potentially deadlock. Because a mutex is a spin-
lock, if a second thread T2 seeks to acquire the mutex lock L0 ,
T2 will monopolize the CPU, T1 will never return into its critical
section and will never release the lock L0 , deadlock
(c) Context switch within a critical section is against mutual exclu-
sion, it allows threads to re-enter a critical section without re-
questing a lock

sol: Nothing happen

16. Mutex lock is a synchronization primitive provided by the OS where the


”acquire()” and ”release()” functions are implemented using a hardware
synchronization primitive such as test-&-set(). Two mutexes M1 and
M2 initialized to 0 are defined in a same process P1 , what could happen
if two different threads execute acquire(M1 ) and acquire(M2 ) almost in
same time?

(a) This is really unfortunate, since both acquire(M1 ) and acquire(M2 )


rely on the same test-&-set() primitive, one will succeed and the
other will fail even though both mutexes are available
(b) test-&-set() is atomic, thus cannot be de-scheduled, the calls to
test-&-set() will be serialized, each thread will be successful get-
ting its mutex
(c) If another process P2 has a mutex with the same name (for exam-
ple M2 ), then M2 will not be available anyway if a thread of P2
executes acquire(M2 ) before P1

sol: test-&-set() is atomic, thus cannot be de-scheduled, the calls to


test-&-set() will be serialized, each thread will be successful getting its
mutex

You might also like