Title: Review: ProducerConsumer using Semaphores
1Review Producer-Consumer using Semaphores
define N 100 // number of slots in the
buffer Semaphore mutex 1 // controls access
to critical region Semaphore empty N //
counts empty buffer slots Semaphore full 0 //
counts full buffer slots void producer(void)
int item while (TRUE) item
produce_item() // generate something to put in
buffer down(mutex) // enter critical
region down(empty) // decrement empty
count insert_item(item) // put new item
in buffer up(mutex) // leave critical
region up(full) // increment count of
full slots void consumer(void) int
item while (TRUE) down(mutex) //
enter critical region down(full) //
decrement full count item remove_item()
// take item from buffer
up(mutex) // leave critical region
up(empty) // increment count of empty slots
Dead Lock!
2Monitor
- Monitor a collection of procedures, variables
and data structures that grouped together - Processes can call procedures in a monitor, but
cannot access its internal variables (private!) - Only one procedure can be active in a monitor at
any instant. (How to guarantee?) - Provide an easy way to achieve mutual exclusion
- Compiler takes charge of mutual exclusion, not
the programmer. - But how about synchronization?(P-C problem)
3Condition Variables
- Two operations
- wait(cond) block the caller on cond. And allow
another process previously prohibited from
entering the monitor to enter now. (avoid
deadlock) - signal(cond) wake up one process blocked on cond
- Only appear as the final statement in a monitor
procedure (why?) - Condition variables are not counters.
- To avoid lost-wakeup problem, the wait must come
before signal.
4Producer-Consumer With Monitors
Monitor ProducerConsumer condition full,
empty integer count procedure
insert(item integer) begin if count
N then wait(full) insert_item(item)
count count 1 if count 1
then signal(empty) end function remove
integer begin if count 0 then
wait(empty) remove remove_item
count count 1 if count N 1 then
signal(full) end count 0 End monitor
Procedure producer Begin while true do
begin item produce_item
ProducerConsumer.insert(item)
end End Procedure consumer Begin while
true do begin item
ProducerConsumer.remove
consume_item(item) end End
Not a system call
5Sleep/Wakeup Vs. Monitor
- Why sleep/wake fails?
- The wake-up call is sent before the sleep call.
- With monitor, that cannot happen
- Only one process can be active in a monitor
- Wait call is always before signal
- Monitors in programming language
- Keyword synchronized in Java
6Message Passing
- Two primitives (system calls)
- Send(destination, message)
- Receive(destination, message)
- Receiver blocks until receiving one message
- Acknowledgement of messages
- Sender resends messages if timeout
- Buffered messages/rendezvous
- Mail box hold up to n messages
- Block senders if mail box is full
- Rendezvous block senders if receivers are not
ready
7Producer-Consumer With Message Passing
define N 100 // number of slots in the
buffer void consumer(void) int item, i
message m for(i 0 i lt N i)
send(producer, m) // send N empties while
(TRUE) receive(producer, m)
item extract_item(m) // extract item from
message send(producer, m) // send
back empty reply void producer(void)
int item message m // message buffer
while (TRUE) item produce_item()
receive(consumer, m) // wait for an empty
to arrive build_message(m, item) //
construct a message to send
send(consumer, m) // send item to consumer
8Barriers Synchronizing A Group
A
B
A
C
B
D
A
C
B
Time ?
D
C
Time ?
D
Time ?
9Summary
- Race conditions
- Critical regions
- Mutual exclusion
- No two processes are in their critical regions at
the same time - Synchronization
- Busy waiting, sleep and wakeup, semaphore, mutex,
monitor, message passing, barrier - Please compare these primitives
10Outline
- Processes
- Threads
- Inter-process communication (IPC)
- Classical IPC problems
- Scheduling
11Dining Philosophers Problem
- Philosophers loop of eating thinking
- Pick up two forks, one at a time
- No predefined order in acquiring folks
- Philosopher ? process forks? resources.
- Goals
- No deadlock
- No starvation
- Efficient
3
3
4
2
4
2
0
1
1
0
12Naïve Solution
define N 5 // number of philosophers Void
philosopher(int j) // j philosopher number,
from 0 to 4 while (TRUE)
think() // philosopher is thinking
take_fork(j) // take left fork, blocked if fork
unavailable take_fork((j1) N) // take
right fork is modulo operator
eat() // yum-yum, spaghetti
put_fork(j) // put left fork back on the
table put_fork((j1) N) // put right
fork back on the table What if all
philosophers take left forks simultaneously? A
deadlock!
13Solutions with Starvation
- What if a philosopher put down left fork if the
right fork is not available? - If all philosophers action simultaneously, the
program runs indefinitely without progress - Starvation!
- All the processes continue to run indefinitely
but fail to make any progress. - Different from deadlock.
- What about waiting for a random time if the right
fork is not available? - May work in practice, low failure probability
- Not absolutely safe!
14Safe Solution May Not Be Good
- Allow at most ONE philosopher eat at a time
- Definitely safe, no competition for forks
- Low efficiency, at least 3 forks are free
- Better solution a philosopher only eat if
neither neighbor is eating - Safe, no starvation, no deadlock.
- Maximal parallelism, at most 2 philosophers can
eat at a time.
15A Solution for Dining Philosopher Problem
define N 5 //number of philosophersdefine
LEFT (iN-1)N //is left numberdefine RIGHT
(i1)N //is right numberdefine THINKING
0 //philosopher is thinkingdefine HUNGRY
1 //philosopher is trying to get forksdefine
EATING 2 //philosopher is eatingint
stateN //array to keep track of everyones
statesemaphore mutex 1
//mutual exclusion for critical regions
semaphore sN 0 //one semaphore per
philosopher void philosopher(int i) //i
philosopher number, from 0 to N-1 while
(TRUE) //repeat forever think()
//philosopher is thinking take_forks(i)
//acquire two forks or block eat()
//eating put_forks(i) //put both forks
back on table
16void take_forks(int i) //i
philosopher number, from 0 to N-1
down(mutex) //enter critical region
stateiHUNGRY //record the fact that
philosopher i is hungry test(i) //try
to acquire 2 forks up(mutex) //exit
critical region down(si) //block
if forks were not acquired void put_forks(int
i) //i philosopher number, from 0 to N-1
down(mutex) //enter critical region
stateiTHINKING //philosopher has
finished eating test(LEFT) //see if
left neighbor can now eat test(RIGHT)
//see if right neighbor can
eat up(mutex) //leave critical region
void test(int i) if (
stateiHUNGRY stateLEFT !EATING
stateRIGHT!EATING) stateieating
up(si)
17Saltshakers Solution
- Previous solution has starvation problem. Why?
- Saltshakers solution adding two tokens to the
table, perhaps saltshakers - each philosopher first collects a saltshaker
before attempting to collect forks, then eats,
and then puts the forks and saltshaker back. A
philosopher has to wait if he/she fails to
collect a saltshaker or a fork. - Deadlock free (why?), starvation free
(assumption?), but less concurrency (how?)
18The Readers and Writers Problem
- Multiple readers/writers of a database
- No access to database when one is writing
- First solution A writer is admitted only if
there is no reader - A writer may never get in!
- Improved solution A writer blocks readers after
her - Less concurrency
19The Sleeping Barber Problem
- One barber, one barber chair, and n chairs for
waiting customers - Barber working or sleeping (semaphore)
- Customer (semaphore)
- If the barber is sleeping, wake him up (lost
signal) - If the barber is cutting others hair
- If there are empty chairs, wait
- Otherwise, leave
- Program the barber and the customers without
getting into race conditions.
20semaphore mutex For mutual exclusion
int waitinga copy of customers
semaphore customers For synchronization
semaphore barbers For synchronization
21semaphore customers 0 //customers waiting
for servicesemaphore barbers 0 //barber
waiting for customerssemaphore mutex 1 //for
mutual exclusionint waiting 0 //customers
are waiting (not being cut)void barber(void)
while (TRUE) down(customers) //go to
sleep if customers is 0 down(mutex)
//acquire access to waiting waitingwaiting-1
//decrement count of waiting customers up(barber
s) //one barber is ready to cut
hair up(mutex) //release waiting cut_hair()
//cut hair void customer(void)
down(mutex) //enter critical region if
( waiting lt CHAIRS) //if no free chair,
leave waitingwaiting1 //increment count
of waiting customers up(customers) //wake up
barber if necessary up(mutex) //release
access to waiting down(barbers) //go to
sleep if barbers0 get_haircut() //be seated
and serviced else up(mutex) //shop
is full, leave