You are on page 1of 28

Critical Problem Revisit

Critical Sections

• Mutual exclusion Only one process can be in the critical section at a


time
Without mutual exclusion, results of multiple execution are not
consistent

• There is a race to execute critical sections

• The sections may be defined by different code in different processes.


Need an OS mechanism so programmer can resolve races

Some Possible OS Mechanisms


 Disable interrupts, Synchronization hardware
 Software solution – locks, semaphores, monitors
Disabling Interrupts
shared double balance;

Code for pi Code for pj


disableInterrupts(); disableInterrupts();
balance = balance + amount; balance = balance - amount;
enableInterrupts(); enableInterrupts();

Disabling interrupts guarantees mutual exclusion, but …


Disadvantages
 A user process can easily abuse this privilege and hence should not be available to
a user process.

 Interrupts could be disabled arbitrarily long

 We only want to prevent pi and pj from interfering with one another; this
prevents any other process pk to execute

 In a Multiprocessor system, disabling interrupts in one processor will not disable


it in another process and hence mutual exclusion is not guaranteed
Hardware Synchronization
TestAndSet()
Swap()

How to use Hardware Synchronization to achieve


mutual exclusion and bounded waiting
Lock

shared boolean lock = FALSE;

Code for pi Code for pj


. . . . . .
acquire(lock); acquire(lock);
<execute critical section>; <execute critical section>;
release(lock); release(lock);
. . . . . .

However, acquire(lock) and release(lock) operations must be atomic !


Important considerations for software locks

 Mutual exclusion:
Only one process at a time in the Critical Section (CS)

 A process should not be delayed access to a critical section when there is


no other process using it

 Once a process attempts to enter its CS, it should not be postponed


indefinitely  NO STARVATION!
(After requesting entry, only a bounded number of other processes may enter before the
requesting process)
Semaphore
• A semaphore, s, is a integer variable that
can only be changed or tested by these
two atomic (indivisible / uninterruptable)
functions:
P(s) (wait(s))
V(s) (signal(s))
Semaphore solution
struct semaphore {
int value;
process *queue;
}

P(semaphore s):
get( )  P( )  wait( )
disable_interrupts();
{ s.value--;
if (s.value < 0)  pthread_mutex_lock()
{place this process in s.queue;
block this process
}
enable_interrupts();
}

V(semaphore s):
{disable_interrupts();
s.value++; release( )  V( )  signal( )
if (s.value <= 0)
{ remove a process P from s.queue;  pthread_mutex_unlock()
wakeup P;
}
enable_interrupts();
}
Shared Account Problem

Pi() Pj()
{ {
. . . . . .
/* Enter the CS */ /* Enter the CS */
P(mutex); P(mutex);
balance += amount; balance -= amount;
V(mutex); V(mutex);
. . . . . .
} }

semaphore mutex = 1;

pthread_create(P0, 0);
pthread_create(P1, 0);
Processing Two Critical Sections
shared lock1 = FALSE; shared lock1 = FALSE;
shared lock2 = FALSE; shared lock2 = FALSE;

Code for p1 Code for p2


. . . . . .

/* Enter CS-1 */ /* Enter CS-2*/


P(lock1); P(lock2);
<critical section 1>; <critical section 2>;
V(lock1); V(lock2);

<other computation>; <other computation>;

/* Enter CS-2 */ /* Enter CS-1 */


P(lock2); P(lock1);
<critical section 2>; <critical section 1>;
V(lock2); V(lock1);

. . . . . .
Deadlock may occur
if locks are not used properly!
shared boolean lock1 = FALSE;
shared boolean lock2 = FALSE;

Code for p1 Code for p2

. . . . . .
P(lock1); P(lock2);

<delete element>; <update length>;

/* Enter CS to update length */ /* Enter CS to add element */

P(lock2); P(lock1);
<update length>; <add element>;

V(lock2); Vlock1);

V(lock1); V(lock2);
. . . . . .
Classical Problems of
Synchronization
Classical Problems of Synchronization
• Bounded-Buffer Producer/Consumer Problem
• Readers and Writers Problem
• Dining Philosophers Problem
Bounded-Buffer Producer/Consumer Problem

• Shared data:
semaphore full, empty, mutex
• Initially:
full = 0, empty = n, mutex = 1
where n is the buffer size
Bounded-Buffer Producer/Consumer Problem

do { The producer must wait


We must make sure that for an empty space in
the producer and the …
the buffer
consumer make changes produce an item
to the shared buffer in a …
mutually exclusive P(empty);
manner P(mutex);

add the item to the buffer

V(mutex);
V(full);

} while (TRUE);
Bounded-Buffer Producer/Consumer Problem

The consumer must wait


for a filled space in the
buffer
do {
P(full)
P(mutex);

remove an item from the buffer

We must make
V(mutex);
sure that the
V(empty); producer and the
… consumer make
consume the item changes to the
… shared buffer in
} while (TRUE); a mutually
exclusive
manner
Readers/Writers Problem
W

R
R
R

• Motivation: Consider a shared database


– Two classes of users:
• Readers – never modify database
• Writers – read and modify database
– Is using a single lock on the whole database sufficient?
• Like to have many readers at the same time
• Only one writer at a time
Readers/Writers Problem
• A database is to be shared among several concurrent processes. Some of
these processes may want only to read the database, whereas others may
want to update the database
• We distinguish between these two types of processes by referring to the
former as readers and to the latter as writers
• Obviously, if two readers access the shared data simultaneously, nothing
bad will happen
• However, if a writer and some other process (either a reader or a writer)
access the database simultaneously, chaos may ensue
Readers/Writers Problem
• To ensure that these difficulties do not arise, we require that the writers
have exclusive access to the shared database
• This synchronization problem has been used to test nearly every new
synchronization primitive
• There are several variations of this problem, all involving priorities
– The first and simplest one, referred to as the first readers/writers problem, requires
that no reader will be kept waiting unless a writer has already obtained permission to
use the shared object (i.e., no reader should wait for other readers to finish simply
because a writer is waiting) NOTE: writers may starve
– The second readers/writers problem requires that, once a writer is ready, that writer
performs its write as soon as possible (i.e., if a writer is waiting, no new readers may
start reading) NOTE: readers may starve
First Readers/Writers Problem
• Shared data:
semaphore mutex, wrt
int readcount
• Initially:
mutex = 1, wrt = 1, readcount =0
First Readers/Writers Problem
A writer will wait if either
do { another writer is
P(wrt); currently writing or one
… or more readers are
writing is performed currently reading

V(wrt);

} while (TRUE);
First Readers/Writers Problem
do{ A reader will wait only if a
writer is currently writing.
P(mutex);
Note that if readcount ==
readcount++;
1, no reader is currently
if (readcount == 1)
reading and thus that is
P(wrt);
the only time that a reader
V(mutex); has to make sure that no
We must make sure … writer is currently writing
that readers update reading is performed (i.e., if readcount > 1, there
the shared variable … is at least one reader
readcount in a P(mutex); reading and thus the new
mutually exclusive readcount--; reader does not have to
manner if (readcount == 0) wait)
V(wrt);
V(mutex);
} while(TRUE);
First Reader/Writer Solution
Reader: Writer:
do{
P(mutex);
do {
readcount++;
if (readcount == 1) P(wrt);
P(wrt); …
V(mutex); writing is perform
… …
reading is performed V(wrt);
… } while (TRUE);
P(mutex);
readcount--; • First reader competes with writers
if (readcount == 0)
V(wrt);
• Last reader signals writers
V(mutex);
• Any writer must wait for all readers
} while(TRUE); • Readers can starve writers
• “Updates” can be delayed forever
not desirable!
Favor Writer
reader() { writer() {
while(TRUE) { while(TRUE) {
<other computing>; <other computing>;
P(mutex2);
P(RD); writeCount++;
P(mutex1); if(writeCount == 1)
readCount++; P(RD);
if(readCount == 1) V(mutex2);
P(WRT); P(WRT);
V(mutex1); access(resource);
V(RD); V(WRT);
P(mutex2)
access(resource); writeCount--;
P(mutex1); if(writeCount == 0)
readCount--; V(RD);
if(readCount == 0) V(mutex2);
V(WRT); }
V(mutex1); }
}
}
• Writers can starve readers
int readCount=0, writeCount=0; • “Reads” can be delayed forever
semaphore mutex1=1, mutex2=1;
semaphore RD=1,WRT=1
Not desirable, either !
Dining Philosophers Problem

• Five philosophers spend their lives thinking and eating


• When a philosopher gets hungry, he/she tries to pick up the
two chopsticks that are closest to him or her. He/she may pick
up only one chopstick at a time. When finished eating, he/she
puts down both chopsticks and starts thinking
• A classic synchronization problem. It is an example of a large
class of concurrency-control problems. It is a simple
representation of the need to allocate several resources
among several processes in a deadlock-free and starvation-
free manner
Dining Philosophers Problem
• Shared data
semaphore chopstick[5]

Initially all values are 1


Dining Philosophers Problem – Philosopher i

do { A philosopher must wait


P(chopstick[i]) for his/her left and right
P(chopstick[(i+1) % 5]) chopsticks to be
available before he/she

can start eating
eat

V(chopstick[i]);
V(chopstick[(i+1) % 5]);

think

} while (TRUE);
Dining Philosophers Problem
• This solution guarantees that no two
neighbors can be eating simultaneously (i.e.,
mutual exclusion)
• Do you see any problem(s) with this solution?
– This solution could create a deadlock. How?

You might also like