Classic Syn Problems

advertisement
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();
balance = balance + amount;
enableInterrupts();
disableInterrupts();
balance = balance - amount;
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
. . .
acquire(lock);
Code for pj
. . .
acquire(lock);
<execute critical section>;
release(lock);
. . .
<execute critical section>;
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):
disable_interrupts();
{
s.value--;
if (s.value < 0)
{place this process in s.queue;
block this process
}
get( )  P( )  wait( )
 pthread_mutex_lock()
enable_interrupts();
}
V(semaphore s):
{disable_interrupts();
s.value++;
if (s.value <= 0)
{ remove a process P from s.queue;
wakeup P;
}
enable_interrupts();
}
release( )  V( )  signal( )
 pthread_mutex_unlock()
Shared Account Problem
Pi()
{
. . .
Pj()
{
. . .
/* Enter the CS */
/* Enter the CS */
P(mutex);
balance += amount;
V(mutex);
. . .
}
P(mutex);
balance -= amount;
V(mutex);
. . .
}
semaphore mutex = 1;
pthread_create(P0, 0);
pthread_create(P1, 0);
Processing Two Critical Sections
shared lock1 = FALSE;
shared lock2 = FALSE;
shared lock1 = FALSE;
shared lock2 = FALSE;
Code for p1
Code for p2
. . .
/* Enter CS-1 */
P(lock1);
<critical section 1>;
V(lock1);
. . .
/* Enter CS-2*/
P(lock2);
<critical section 2>;
V(lock2);
<other computation>;
<other computation>;
/* Enter CS-2 */
/* Enter CS-1 */
P(lock2);
<critical section 2>;
V(lock2);
. . .
P(lock1);
<critical section 1>;
V(lock1);
. . .
Deadlock may occur
if locks are not used properly!
shared boolean lock1 = FALSE;
shared boolean lock2 = FALSE;
Code for p1
. . .
P(lock1);
Code for p2
. . .
P(lock2);
<delete element>;
<update length>;
/* Enter CS to update length */
/* Enter CS to add element */
P(lock2);
<update length>;
P(lock1);
<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
We must make sure that
the producer and the
consumer make changes
to the shared buffer in a
mutually exclusive
manner
do {
…
produce an item
…
P(empty);
P(mutex);
…
add the item to the buffer
…
V(mutex);
V(full);
} while (TRUE);
The producer must wait
for an empty space in
the buffer
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
…
V(mutex);
V(empty);
…
consume the item
…
} while (TRUE);
We must make
sure that the
producer and the
consumer make
changes to the
shared buffer in
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
do {
P(wrt);
…
writing is performed
…
V(wrt);
} while (TRUE);
A writer will wait if either
another writer is
currently writing or one
or more readers are
currently reading
First Readers/Writers Problem
do{
We must make sure
that readers update
the shared variable
readcount in a
mutually exclusive
manner
P(mutex);
readcount++;
if (readcount == 1)
P(wrt);
V(mutex);
…
reading is performed
…
P(mutex);
readcount--;
if (readcount == 0)
V(wrt);
V(mutex);
} while(TRUE);
A reader will wait only if a
writer is currently writing.
Note that if readcount ==
1, no reader is currently
reading and thus that is
the only time that a reader
has to make sure that no
writer is currently writing
(i.e., if readcount > 1, there
is at least one reader
reading and thus the new
reader does not have to
wait)
First Reader/Writer Solution
Reader:
do{
P(mutex);
readcount++;
if (readcount == 1)
P(wrt);
V(mutex);
…
reading is performed
…
P(mutex);
readcount--;
if (readcount == 0)
V(wrt);
V(mutex);
} while(TRUE);
Writer:
do {
P(wrt);
…
writing is perform
…
V(wrt);
} while (TRUE);
• First reader competes with writers
• Last reader signals writers
• Any writer must wait for all readers
• Readers can starve writers
• “Updates” can be delayed forever
not desirable!
Favor Writer
reader() {
writer() {
while(TRUE) {
<other computing>;
while(TRUE) {
<other computing>;
P(mutex2);
writeCount++;
if(writeCount == 1)
P(RD);
V(mutex2);
P(WRT);
access(resource);
V(WRT);
P(mutex2)
writeCount--;
if(writeCount == 0)
V(RD);
V(mutex2);
}
P(RD);
P(mutex1);
readCount++;
if(readCount == 1)
P(WRT);
V(mutex1);
V(RD);
access(resource);
P(mutex1);
readCount--;
if(readCount == 0)
V(WRT);
V(mutex1);
}
}
}
int readCount=0, writeCount=0;
semaphore mutex1=1, mutex2=1;
semaphore RD=1,WRT=1
• Writers can starve readers
• “Reads” can be delayed forever
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 starvationfree manner
Dining Philosophers Problem
• Shared data
semaphore chopstick[5]
Initially all values are 1
Dining Philosophers Problem – Philosopher i
do {
P(chopstick[i])
P(chopstick[(i+1) % 5])
…
eat
…
V(chopstick[i]);
V(chopstick[(i+1) % 5]);
…
think
…
} while (TRUE);
A philosopher must wait
for his/her left and right
chopsticks to be
available before he/she
can start eating
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?
Download