semaphores
semaphores
Carsten Griwodz
University of Oslo
(including slides by Otto Anshus and Kai Li)
Critical Regions
• Process • Thread
– Address space – Program counter
– Program text and data – Registers
– Open files – Stack
– Child process IDs
– Alarms
– Signal handlers
– Accounting information • Implemented in kernel or in
user space
• Implemented in kernel • Threads are the scheduled
entities
Producer-Consumer Problem
Unbounded PCP
• Mutexes
– Can be implemented using busy waiting
– Simpler with advanced atomic operations
• Disable interrupts, TSL, XCHG, …
– Still many approaches using busy waiting
– Better implemented using system calls block & unblock
Bounded PCP
out
in
Rules for the buffer B:
Capacity: N •No Get when empty
•No Put when full
GET (buf)
PUT (msg) •B shared, so must have
mutex between Put and
Get
Producer Consumer
Mutex Solution
Put(msg) { Get(msg) {
acquire(mutex); acquire(mutex);
<put> while(empty) {
release(mutex); release(mutex);
Unbounded PCP } acquire(mutex);
}
<get>
release(mutex);
Busy waiting }
Put(msg) { Get(msg) {
acquire(mutex); acquire(mutex);
while(full) { while(empty) {
release(mutex); release(mutex);
Bounded PCP acquire(mutex); acquire(mutex);
} }
<put> <get>
release(mutex); release(mutex);
} }
Acquire will
block first caller
until Release SIGNAL
Sleep and Wakeup / Signal and Wait
while(1) { while(1) {
<process> if(empty)
acquire(mutex); wait(cond);
<insert> acquire(mutex);
release(mutex); <remove>
signal(cond); release(mutex);
} <process>
}
Unbounded PCP using Signal and Wait
Q
GET (buf):
PUT (msg):
Producer Consumer
while(1) { while(1) {
<process> if(empty)
acquire(mutex); wait(cond);
<insert> acquire(mutex);
release(mutex); <remove>
signal(cond); release(mutex);
} <process>
}
Lost signal
GET (buf):
PUT (msg):
Producer Consumer
while(1) { while(1) {
<process> acquire(mutex);
acquire(mutex); while(empty) {
<insert> wait(cond);
signal(cond); release(mutex);
release(mutex); acquire(mutex);
} Producer can’t enter }
<remove>
release(mutex);
<process>
}
Unbounded PCP using Signal and Wait
Q
GET (buf):
PUT (msg):
Producer Consumer
while(1) { while(1) {
<process> acquire(mutex);
acquire(mutex); while(empty) {
<insert> release(mutex);
signal(cond); wait(cond);
release(mutex); acquire(mutex);
} }
<remove>
Lost signal release(mutex);
<process>
}
P(s) { V(s) {
if (--s < 0) if (++s <= 0)
Block(s); Unblock(s);
} }
P(s): V(s):
while (s <= 0) {};
s++;
s--;
ATOMIC
• Starvation possible?
s integer Threads waiting to get return after calling P (s) when s was <=0
sem_wait_queue
V (s) P (s)
Unblock Block
(FIFO is fair)
+1 -1
Simple to debug?
A x := 0; B
P (x); y := 0;
P (y);
….. …..
V (y); V (x);
PUT (msg): GET (buf): •Is Mutex needed when only 1 P and 1 C?
P(mutex); P(nonempty); •PUT at one end, GET at other end
<insert> P(mutex);
V(mutex); <remove>
V(nonempty); V(mutex);
Bounded PCP using Semaphores
Rules for the buffer B: One semaphore for each
out
condition we must wait
B •No Get when empty for to become TRUE:
in •No Put when full •B empty: nonempty:=0;
Capacity: N •B shared, so must have •B full: nonfull:=N
mutex between Put and
Get •B mutex: mutex:=1;
GET (buf):
PUT (msg):
Producer Consumer
PUT (msg): GET (buf): •PUT at one end, GET at other end
P(nonfull); P(nonempty);
P(mutex); P(mutex);
<insert> <remove>
V(mutex); V(mutex);
V(nonempty); V(nonfull);
• Five philosopher
• Five dishes
• Five forks
• But a philosopher needs two forks for eating
Ti
Get L; Get R if free else Put L;
•Starvation possible
Dining Philosophers
To avoid starvation they could look after each other:
s state
•Entry: If L and R is not eating we can •Thinking
•Eating
•Exit: If L (R) wants to eat and L.L (R.R) is not
i+1 •Want
i i+1 eating we start him eating
S() = 0 initially
i P(mutex);
state(i):=Want;
if (state(i-1) !=Eating AND state(i+1) != Eating)
Ti {/*Safe to eat*/
While (1) { state(i):=Eating;
V(s(i)); /*Because */ }
<think> V(mutex);
ENTRY; P(s(i)); /* Init was 0!!
<eat> We or neighbor must say V(i) to us!*/
EXIT;
} P(mutex);
state(i):=Thinking;
if (state(i-1)=Want AND state(i-2)
!=Eating)
{
state(i-1):=Eating;
V(s(i-1)); /*Start Left neighbor*/
}
/*Analogue for Right neighbor*/
V(mutex);
Dining Philosophers
s
S(i) = 1 initially
• Several threads
• Shared data in a critical region
• Init( ec )
– Set the eventcount to 0
• Read( ec )
– Return the value of eventcount ec
• Advance( ec )
– Atomically increment ec by 1
• Await( ec, v )
– Wait until ec >= v
Bounded PCP with Event Count
out
in=out=0;
B
producer() { consumer() { in
int next = 0; int next = 0;
Capacity: N
Condition Variables
GET (buf):
PUT (msg):
Producer Consumer
while(1) { while(1) {
<process> P(mutex);
P(mutex); while(empty) {
<insert> wait(cond,mutex);
signal(cond); }
V(mutex); <remove>
} V(mutex);
No problems
<process>
}
GET (buf):
PUT (msg): while(1) {
Consumer
P(mutex);
Producer
while(empty) {
wait(cond,mutex);
}
while(1) { <remove>
<process> V(mutex);
P(mutex); <process>
<insert> }
signal(cond);
V(mutex); while(1) {
} P(mutex);
while(empty) {
wait(cond,mutex);
}
<remove>
No problems either V(mutex);
<process>
}
Emulations
• Emulations
wait(cond,mutex) { signal(cond) {
P(cond.lock); P(cond.lock);
cond.waiters+=1; if(cond.waiters>0) {
V(cond.lock); V(cond.signal);
V(mutex); But no lost signal V(cond.unlock);
P(cond.signal); because of } else {
P(cond.lock); cond.waiters & V(cond.unlock);
cond.waiters-=1; counting in }
V(cond.lock); semaphores }
P(mutex);
}
Looks like lost-signal situation in
signal-and-wait
Condition Variables Extension
wait(cond,mutex) { broadcast(cond) {
P(cond.lock); P(cond.lock);
cond.waiters+=1; if(cond.waiters>0) {
V(cond.lock); for(i=0;i<cond.waiters;i++)
V(mutex); V(cond.signal);
P(cond.signal); V(cond.unlock);
P(cond.lock); } else {
cond.waiters-=1; V(cond.unlock);
V(cond.lock); }
P(mutex); }
}
Condition Variables Extension II
V(sem) { P(sem) {
acquire(sem.mutex); acquire(sem.mutex);
sem.val += 1; sem.val -= 1;
if(sem.val <= 0) if(sem.val < 0)
signal(sem.cond); wait(sem.cond,sem.mutex);
release(sem.mutex); release(sem.mutex);
} }
Barriers
• Use of a barrier
– threads approaching a barrier
– all threads but one blocked at barrier
– last thread arrives, all are let through