You are on page 1of 37

Process Synchronization:

Semaphores & Mutex

1
Cooperating Processes
• Multiprogramming created an environment for
concurrent processes to execute
• Concurrent processes executing in the operating system
allows for the processes to cooperate with other
processes.
• Processes are cooperating if they can affect each other.
• The simplest example of how this can happen is where
two processes are using the same file. One process may
be writing to a file, while another process is reading from
the file; so, what is being read may be affected by what is
being written.
• Cooperation & Sharing is important for several reasons:
– Information sharing, computation speedup, modularity,
convenience
• cooperating processes are processes that
cooperate to achieve a specific task.
• A task is initially broken into subtasks , each
subtask is assigned to a process that should pass
the result (or input) to another process and so on,
until the task is done.
• Multiple cooperating processes introduce the
potential for new synchronization problems in
software implementation called Critical section
Synchronization problems
• These synchronization problems can occur
whenever two or more concurrent
processes use any shared resource.
• How these synchronization problems arise
in concurrent applications?
• Abstract mechanism that can be used to
solve synchronization problems.
Critical sections
• A real life example
– In automobile transportation, intersections are
part of a street, but they are unique part of the
street because the intersection is a shared
between two different streets.
– The traffic intersection is a critical section of
these two streets, in the sense that only one
vehicle can be in the intersection at a time.
– Eithor vehicle can use the critical section,
provided that the others is not using it
Traffic Intersections
Critical section
Critical sections
• Critical sections occur in concurrent software
whenever two processes access a common
shared variable

• Like bus and car, certain parts of the code are


the software critical sections

• Suppose 2 processes p1 & p2, execute


concurrently to access a common integer
variable balance
Critical Sections
shared double balance;

Code for p1 Code for p2


. . . . . .
balance = balance + amount; balance = balance -
amount;
. . . . . .

balance+=amount balance-=amount

balance
Compiled instructions
code schema for p1 code schema for p2

load R1, balance load R1, balance


load R2, amount load R2, amount
add R1, R2 sub R1, R2
store R1, balance store R1, balance
Critical Sections
Execution of p1 Execution of p2

load R1, balance
load R2, amount
Timer interrupt …
load R1, balance
load R2, amount
sub R1, R2
store R1, balance

Timer interrupt
add R1, R2
store R1, balance

Critical Sections
• Mutual exclusion: Only one process can be in the
critical section at a time
• There is a race to execute critical sections
• Need an OS level (abstract level) mechanism so
programmer can resolve races
Race condition
• The programs defining p1 & p2 have a critical
section with respect to their use of the shared
variable balance
• For p1 critical section is the computing the sum of
balance and amount. But for p2 it is for
computing the difference of balance and amount
• We say that there is a race condition between p1
and p2, because the outcome of the computation
depends on the relative times that the two
processes execute their respective critical sections
Race Condition
• The condition where data consistency is lost
because of lack of synchronization of the
component task of a system is called a race
condition
• To avoid this problem, shared global variables
must be used only with synchronization
Critical section code
Process {
while (true) {
ENTER CRITICAL SECTION
Access shared variables;
LEAVE CRITICAL SECTION
Do other work
}
}

14
Boolean Flag

15
A Semaphore
Dijkstra Semaphore
• Semaphore is an OS abstract type that
performs operations similar to the traffic
light.
• Invented in the 1960s
• Conceptual OS mechanism, with no specific
implementation defined
• Basis of all contemporary OS
synchronization mechanisms
Semaphore
• Semaphore is a non negative integer
variable whose values can be changed only
by one of the two indivisible access routines
P() & V()

• P () : Proberen - to test

• V() : Verhogen - to increment


Semaphore
• Semaphore s = 1;
• P(s)
{ while (s==0) {wait};
s = s – 1; }
• V(s) { s = s + 1;}

• A semaphore restricts the number of


simultaneous users of a shared resource up to a
maximum number
Race condition
Proc_0() { proc_1() {
while(TRUE) { while(TRUE {
<compute section>; <compute section>;
<critical section>; <critical section>;
} }
} }

<shared global declarations>


<initial processing>
fork(proc_0, 0);
fork(proc_1, 0);
Solving the Canonical Problem
Proc_0() { proc_1() {
while(TRUE) { while(TRUE {
<compute section>; <compute section>;
P(mutex); P(mutex);
<critical section>; <critical section>;
V(mutex); V(mutex);
} }
} }

semaphore mutex = 1;
fork(proc_0, 0);
fork(proc_1, 0);
Shared Account Balance Problem
Proc_0() { proc_1() {
. . . . . .
/* Enter the CS */ /* Enter the CS */
P(mutex); P(mutex);
balance += amount; balance -= amount;
V(mutex); V(mutex);
. . . . . .
} }

semaphore mutex = 1;

fork(proc_0, 0);
fork(proc_1, 0);
Types of Semaphore
• Binary Semaphore
– They can takes only 2 values - 0 &1

• Counting Semaphore
– counting semaphores take more than two
values, they can have any value you want. The
max value X they take allows X process/threads
to access the shared resource simultaneously.
Mutex
• Simplest and most efficient thread synchronization
mechanism
• Like a semaphore with maximal value 1
• A special variable that can be either in
– locked state: a distinguished thread that holds or
owns the mutex; or
– unlocked state: no thread holds the mutex
• When several threads compete for a mutex, one wins.
The rest block at that call
Classical Synchronization Problems

• Dining philosophers problem


• Producers-consumers problem
• Readers-writers problem
• Sleeping barber problem
• Cigarette smokers problem
Readers-writers problem
• Here a resource is to be shared among a
community of processes of distinct types :
Readers and Writers,
– A reader process can share the resource with
any other reader process, but not with any
writer process
– A writer process requires exclusive access to
the resource whenever it acquires any access
to the resource
 Eg: a file is to be shared among a set of
processes
Readers-Writers Problem

Writers

Readers
Readers-Writers Problem (2)

Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader
Reader

Shared Resource
Readers-Writers Problem (3)
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Writer

Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Shared Resource
Readers-Writers Problem (4)
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader Writer
Writer
Reader
Reader
Reader
Reader

Writer
Writer

Shared Resource
First Solution
• As long as the reader holds the resource and
there are new readers arriving, any writer
must wait for the resource become available.
– The first reader accessing the shared resource
must compete with any writers, but once a reader
succeeds, other readers can pass directly into the
critical section, provided that at least one reader is
in the critical section
– Readers keep the count of the no. of readers in
the critical section, with the readcount variable
which is updated and tested inside its own critical
section
reader() {
First Solution writer() {
while(TRUE) { while(TRUE) {
<other computing>; <other computing>;
P(mutex); P(writeBlock);
readCount++; /* Critical section */
if(readCount == 1) access(resource);
P(writeBlock); V(writeBlock);
V(mutex); }
/* Critical section */ }
access(resource);
P(mutex);
readCount--;
if(readCount == 0) •First reader competes with writers
V(writeBlock); •Last reader signals writers
V(mutex);
}
}
resourceType *resource;
int readCount = 0;
semaphore mutex = 1;
semaphore writeBlock = 1;
fork(reader, 0);
fork(writer, 0);
First Solution
reader() { writer() {
while(TRUE) { while(TRUE) {
<other computing>; <other computing>;
P(mutex); P(writeBlock);
readCount++; /* Critical section */
if(readCount == 1) access(resource);
P(writeBlock); V(writeBlock);
V(mutex); }
/* Critical section */ }
access(resource);
P(mutex);
readCount--;
if(readCount == 0) •First reader competes with writers
V(writeBlock); •Last reader signals writers
V(mutex);
} •Any writer must wait for all readers
} •Readers can starve writers
resourceType *resource;
int readCount = 0; •“Updates” can be delayed forever
semaphore mutex = 1; •May not be what we want
semaphore writeBlock = 1;
fork(reader, 0);
fork(writer, 0);
Precedence to writer process

34
reader() {
Writer Precedence writer() {
while(TRUE) { while(TRUE) {
<other computing>; <other computing>;
4 P(writePending); P(mutex2);
P(readBlock); writeCount++;
P(mutex1); if(writeCount == 1)
readCount++; 3 P(readBlock);
2 if(readCount == 1) V(mutex2);
P(writeBlock); P(writeBlock);
V(mutex1); access(resource);
V(readBlock); V(writeBlock);
1 V(writePending); P(mutex2)
access(resource); writeCount--;
P(mutex1); if(writeCount == 0)
readCount--; V(readBlock);
if(readCount == 0) V(mutex2);
V(writeBlock); }
V(mutex1); }
}
}
int readCount = 0, writeCount = 0;
semaphore mutex = 1, mutex2 = 1;
semaphore readBlock = 1, writeBlock = 1, writePending = 1;
fork(reader, 0);
fork(writer, 0);
Implementing Semaphores: Test and Set Instruction
• “TS R3, m “ loads register R3 tests its value and writes a TRUE back to location m.
• OS function - TS(m): [Reg_i = memory[m]; memory[m] = TRUE;]

Data CC Data CC
Register Register Register Register
R3 … … R3 FALSE =0

m FALSE m TRUE

Primary Primary
Memory Memory

(a) Before Executing TS


(b) After Executing TS
Using the TS Instruction

boolean s = FALSE; semaphore s = 1;


. . . . . .
while(TS(s)) ; P(s) ;
<critical section> <critical section>
s = FALSE; V(s);
. . . . . .

You might also like