4. Process Synchronization
4. Process Synchronization
Synchronization
Process Synchronization means
coordinating the execution of processes
such that no two processes access the
same shared resources and data.
It is required in a multi-process system
where multiple processes run together,
and
For more than oneAprocess
example: processtriesP1
to gain
tries
access to the same shared resource or
changing data in a particular memory
data at the same time.
location. At the same time another
process P2 tries reading data from the
Sections of a Program
1. Entry Section: This decides the entry of
any process.
register2 = count
register2 = register2 - 1
count = register2
Race Consider this execution interleaving with “count = 5” initially:
Condition S0: producer execute register1 = count {register1 = 5}
S1: producer execute register1 = register1 + 1 {register1 =
6}
S2: consumer execute register2 = count {register2 = 5}
S3: consumer execute register2 = register2 - 1 {register2 =
4}
S4: producer execute count = register1 {count = 6 }
S5: consumer execute count = register2 {count = 4}
Rules for Critical Section
1. Mutual Exclusion: Only one process at a time can be executing in their
critical section.
2. Progress: If no process is currently executing in their critical section, and
one or more processes want to execute their critical section, then only the
processes not in their remainder sections can participate in the decision, and
the decision cannot be postponed indefinitely. ( i.e. processes cannot be
blocked forever waiting to get into their critical sections. )
3. Bound Waiting: There exists a limit as to how many other processes can
get into their critical sections after a process requests entry into their critical
section and before that request is granted. ( i.e. a process requesting entry
into their critical section will get a turn eventually, and there is a limit as to
how many other processes get to go first. )
Solution to The Critical
Section
1. Peterson Solution: If a process executes
in a critical state, the other process can only execute the rest of
the code and vise-versa. This method developed by Peterson is
widely used and helps make sure that only one process runs at a
specific time in the critical section.
Example: Let there be N processes (P1, P2, … PN) such that at some point of
time every process needs to enter the Critical Section. There is a FLAG[]
array of size N that is false by default. Therefore, the flag of a process needs
to be set true, whenever it wants to enter the critical section.
A variable TURN tells the process number waiting to enter the Critical
Section. When a process enters the critical section it changes the TURN to
another number from the list of ready processes when it is exiting.
Peterson Solution
PROCESS Pi
FLAG[i] = true
while( (turn != i) AND (CS is !free) ){ wait;
}
CRITICAL SECTION FLAG[i] = false
turn = j; //choose another process
Peterson Solution
To prove that the solution is correct, we must examine the three conditions listed above:
• Mutual exclusion - If one process is executing their critical section when the other wishes
to do so, the second process will become blocked by the flag of the first process. If both
processes attempt to enter at the same time, the last process to execute "turn = j" will be
blocked.
• Progress - Each process can only be blocked at the while if the other process wants to use
the critical section ( flag[ j ] = = true ), AND it is the other process's turn to use the critical
section ( turn = = j ). If both of those conditions are true, then the other process ( j ) will be
allowed to enter the critical section, and upon exiting the critical section, will set flag[ j ] to
false, releasing process i. The shared variable turn assures that only one process at a time
can be blocked, and the flag variable allows one process to release the other when exiting
their critical section.
Peterson Solution
• Bounded Waiting - As each process enters their entry section, they
set the turn variable to be the other processes turn. Since no process
ever sets it back to their own turn, this ensures that each process will
have to let the other process go first at most one time before it
becomes their turn again.
•Note that the instruction "turn = j" is atomic, that is it is a single machine
instruction which cannot be interrupted.
Solution to The Critical
Section
2. Synchronization Hardware:
Hardware can also help resolve the problems of critical sections
sometimes. Some OS offer lock functionality. This gives a process
a lock when it enters the critical section and releases the lock
after it leaves a critical section. Due to this other processes can’t
enter a critical section when a process is already inside.
2. Synchronization
Hardware
The examples satisfy the mutual
exclusion requirement, but
unfortunately do not guarantee
bounded waiting. If there are multiple
processes trying to get into their critical
sections, there is no guarantee of what
order they will enter, and any one
process could have the bad luck to wait
forever until they got their turn in the
critical section.
2. Synchronization
Hardware
Example
WAIT ( S ):
while ( S <= 0 );
S = S - 1;
SIGNAL ( S ):
S = S + 1;
Types of Semaphore
semaphores can take on one of two forms:
Binary semaphores can take on one of two values, 0 or 1. They can be used to
solve the critical section, and can be used as mutexes on systems that do not
provide a separate mutex mechanism.
Binary Semaphore
struct semaphore Signal (semaphore s)
{ {
enum value (0,1); if (s.L is empty)
Queue type L; {
} s.value=1;
Wait (semaphore s) }
{ else
if (s.value == 1) {
{ select a process
s.value=0; (PCB) from s.L;
} wake up();
else }
{ }
put process
(PCB) in s.L;
sleep();
}
}
Binary Semaphore :
Problems
Each process Pi, i = 1, 2, …, 9 is coded as follows-
repeat
P(mutex)
{ Critical Section }
V(mutex)
forever
The code for P10 is identical except that it uses V(mutex) in place of P(mutex). What is the
largest number of processes that can be inside the critical section at any moment?
1.1
2.2
3.3
4.None of these
Types of Semaphore
Counting semaphores can take on any integer value, and are usually used to
count the number remaining of some limited resource.
The counter is initialized to the number of such resources available in the
system, and whenever the counting semaphore is greater than zero, then a
process can enter a critical section and use one of the resources.
When the counter gets to zero ( or negative in some implementations ), then
the process blocks until another process frees up a resource and increments the
counting semaphore with a signal call.
Types of Semaphore
• Semaphores can also be used to synchronize certain operations between processes. For example,
suppose it is important that process P1 execute statement S1 before process P2 executes statement
S2.
• First, we create a semaphore named synch that is shared by the two processes and initialize it
to zero. Then in process P1 we insert the code:
S1;
signal( synch );
•and in process P2 we insert the code:
wait( synch );
S2;
• Because synch was initialized to 0, process P2 will block on the wait until after P1 executes
the call to signal.
Counting Semaphore
struct semaphore Signal (semaphore s)
{ {
int value; s.value = s.value + 1;
Queue type L; if (s.value <=0 )
} {
Wait (semaphore s) select a process (PCB) from
{ L;
s.value = s.value - 1; wake up();
if (s.value < 0) }
{ }
put process
(PCB) in L;
sleep();
}
else
return;
}
Counting Semaphore :
Problems
A counting semaphore S is initialized to 10. Then, 6 P operations and 4 V operations are
performed on S. What is the final value of S?
Solution-
• P operation also called as wait operation decrements the value of semaphore variable by 1.
• V operation also called as signal operation increments the value of semaphore variable by 1.
Thus,
Final value of semaphore variable S
= 10 – (6 x 1) + (4 x 1)
= 10 – 6 + 4
=8
Deadlock and Starvation
One important problem that can arise when using semaphores to block processes
waiting for a limited resource is the problem of deadlocks, which occur when
multiple processes are blocked, each waiting for a resource that can only be freed
by one of the other ( blocked ) processes, as illustrated in the following example.
Deadlock and Starvation
Another problem to consider is that of starvation, in which one or more
processes gets blocked forever, and never get a chance to take their turn in the
critical section.
For example, in the semaphores above, we did not specify the algorithms for
adding processes to the waiting queue in the semaphore in the wait( ) call, or
selecting one to be removed from the queue in the signal( ) call. If the method
chosen is a FIFO queue, then every process will eventually get their turn, but if a
LIFO queue is implemented instead, then the first process to start waiting could
starve.
Priority Inversion
A challenging scheduling problem arises when a high-priority process gets blocked waiting for
a resource that is currently held by a low-priority process.
If the low-priority process gets pre-empted by one or more medium-priority processes, then
the high-priority process is essentially made to wait for the medium priority processes to finish
before the low-priority process can release the needed resource, causing a priority
inversion. If there are enough medium-priority processes, then the high-priority process may
be forced to wait for a very long time.
One solution is a priority-inheritance protocol, in which a low-priority process holding a
resource for which a high-priority process is waiting will temporarily inherit the high priority
from the waiting process. This prevents the medium-priority processes from preempting the
low-priority process until it releases the resource, blocking the priority inversion problem.
Classic Problems of
Synchronization
The Dining-
Philosophers Problem
put_fork[i];
put_fork[ (i+1) % 5] ;
THINKING
}
}
Semaphore Solution to The
Dining-Philosophers
Semaphore is simply a non-negative variable that is shared between threads. A
Problem
semaphore is a signalling mechanism, and another thread can signal a thread waiting
on a semaphore.
void Philosopher
{ Semaph Left Right
while(1) ore pick pick
{ F0 Co C1
wait(take_fork F[i]);
F1 C1 C2
wait (take_fork[ F(i+1) % 5]) ;
F2 C2 C3
EATING THE NOODLE F3 C3 C4
F4 C4 C0
put_fork(F[i]);
put_fork( F[i+1] % 5) ;
THINKING
}
}
Drawback of Semaphore
Solution
The disadvantage of the above approach is that it may result in
a deadlock situation. This occurs when all of the philosophers
pick their left fork at the same time, resulting in a deadlock
situation in which none of the philosophers can eat.
Solution to Avoid
Deadlock
The maximum number of philosophers on the table should not
exceed four.
Only when both Forks (left and right) are available at the
same moment can a philosopher be permitted to choose their
Forks.
A philosopher in an even position should choose the right Fork
first, followed by the left Fork, whereas a philosopher in an
odd situation should choose the left Fork first, followed by the
right Fork.
The four beginning philosophers (P0, P1, P2, and P3) should
The Readers Writers
Problem
The readers-writers problem is related to an object(such
as a file or a database) that is shared by numerous
processes.
Some of these processes are readers, meaning they only
want to read data from the object, while others are writers,
meaning they want to write data into the object.
The readers-writers problem is used to maintain
synchronization so that the object data is not corrupted.
The Readers Writers
Problem
There are several variations to the readers-writers problem, most centered around relative
priorities of readers versus writers.
• The first readers-writers problem gives priority to readers. In this problem, if a reader
wants access to the data, and there is not already a writer accessing it, then access is
granted to the reader. A solution to this problem can lead to starvation of the writers,
as there could always be more readers coming along to access the data.
• The second readers-writers problem gives priority to the writers. In this problem,
when a writer wants access to the data it jumps to the head of the queue - All waiting
readers are blocked, and the writer gets access to the data as soon as it becomes
available. In this solution the readers may be starved by a steady stream of writers.
The Readers Writers
Problem
The Solution
We will make use of two semaphores and an integer variable:
1. mutex, a semaphore (initialized to 1), is used to ensure mutual
exclusion when
readCount is updated, i.e., when any reader enters or exits from
the critical section.
2. wrt, a semaphore (initialized to 1) common to both reader and
writer processes.
3. readCount, an integer variable (initialized to 0) that keeps track of
how many
processes are currently reading the object.
The Reader Process
1. The reader requests entry to the critical section.
2. If permitted,
it increments the number of readers within the critical section. If this reader
is the first to enter, the wrt semaphore is locked, preventing writers from
entering if any other reader is present.
it then signals mutex, indicating that any new reader may enter while
others are currently reading.
it leaves the critical section after reading. When departing, it checks to see
whether there are any more readers within and if there are, it signals the
semaphore "wrt," indicating that the writer can now enter the critical
region.
3. If it is not permitted, it will continue to wait.
The Reader Process
do {
// The reader requests entry to the critical section
wait(mutex);
//Now,the number of readers has incremented by 1
readCount++;
// there is minimum one reader in the critical section
// this ensures that no writer can enter if there is
even one reader
// hence readers are given preference here
if (readCount==1)
wait(wrt);
// other readers can enter while the current reader is
inside the critical section
signal(mutex);
// current reader performs reading
wait(mutex); // a reader wants to exit
readCount--;
// i.e., no reader is left in the critical section,
if (readCount == 0)
signal(wrt); // writers can enter now
signal(mutex); // reader exits
The Writer Process
1. The writer requests entry to the critical section.
2. If permitted, i.e., wait() returns a true value, it enters and
performs the write.
3. If it is not allowed, it will continue to wait.
4. It gets out of the critical section.
The Writer Process
do {
// the writer requests entry to the
critical section
wait(wrt);
// performs the write
// exits the critical section
signal(wrt);
} while(true);
The Sleeping Barber
Problem
• Dijkstra introduced the sleeping barber problem in 1965.
• This problem is based on a hypothetical scenario where there is a
barbershop with one barber.
• The barbershop is divided into two rooms, the waiting room, and
the workroom.
• The waiting room has n chairs for waiting customers, and the
workroom only has a barber chair.
Solution to The Sleeping
Barber Problem
The following solution uses three semaphores, one for
customers(for counts of waiting for customers), one for barber(a
binary semaphore denoting the state of the barber, i.e., 0 for idle
and 1 for busy), and a mutual exclusion semaphore, mutex for
seats.
Semaphore Customers = 0; // semaphore for count of customers
int FreeSeats = N;
Solution to The Sleeping
Barber Problem
Barber {
while(true) {