8-Semaphores, Monitors, and Message Passing: Producer/Consumer With Sleep/Wakeup
8-Semaphores, Monitors, and Message Passing: Producer/Consumer With Sleep/Wakeup
Mark Handley
1
Semaphores (Dykstra, 1965)
int s;
wait
waitisissometimes
sometimes
wait(s) { known
knownas asdown,
down,ororPP
while (s == 0) { /* no-op */ } signal
signalisissometimes
sometimes
s--; known
knownas asup,
up,or
orVV
}
signal(s) {
s++;
}
Using Semaphores
int mutex = 1;
while (TRUE) {
wait(mutex);
critical section
signal(mutex);
non-critical section This is known
} as a mutex lock
2
Using Semaphores
A semaphore can be used to ensure that one section of code is
run before another section, even when they’re in different
processes.
Process 1: Process 2:
int signal = 0;
Implementing Semaphores
typedef
typedefstruct
struct{{
int value;
int value;
struct
structprocess
process*L;
*L;
}}semaphore;
semaphore;
void
voidwait(semaphore
wait(semaphoreS) S){{ void
voidsignal(semaphore
signal(semaphoreS) S){{
S.value--;
S.value--; S.value++;
S.value++;
ifif(S.value
(S.value<<0)0){{ ifif(S.value
(S.value<=
<=0)0){{
add
addthis
thisprocess
processtotoS.L;
S.L; remove
removeaaprocess
processPPfrom
fromS.L;
S.L;
sleep();
sleep(); wakeup(P);
wakeup(P);
}} }}
}} }}
3
Implementing a Mutex using TSL
User-space thread implementation
mutex_lock:
TSL Register, Mutex // copy mutex to Register, set Mutex to 1
CMP Register, 0 // test if mutex was zero
JZE ok // it is was, mutex wasn’t locked, so return
CALL thread_yield // mutex is busy: schedule another thread
JMP mutex_lock // loop and try again
ok: RTN // return to caller, and enter critical section
mutex_unlock:
MOVE Mutex, 0 // clear the lock
RTN // return to caller
void
voidproducer()
producer(){{ void
voidconsumer()
consumer(){{
while
while(TRUE)
(TRUE){{ while
while(TRUE)
(TRUE){{
int
intitem
item==produce_item();
produce_item(); wait(&full);
wait(&full);
wait(&empty);
wait(&empty); wait(&mutex);
wait(&mutex);
wait(&mutex);
wait(&mutex); item
item==remove_item();
remove_item();
insert_item(item);
insert_item(item); signal(&mutex);
signal(&mutex);
signal(&mutex);
signal(&mutex); signal(&empty);
signal(&empty);
signal(&full);
signal(&full); consume_item(item);
consume_item(item);
}} }}
}} }}
4
Problems with Semaphores (2)
Monitors
Hoare’s response to Dijkstra’s semaphores
Higher-level
Structured
Monitors encapsulate data structures that are not
externally accessible
Mutual exclusive access to data structure enforced
by compiler or language run-time.
5
Monitors
Monitors are a high-level synchronization primitive:
monitor monitor-name
{
Key points:
shared variable declarations
• Shared variables are only
procedure P1 ( ... ) {
... accessible through the
} monitor’s procedures.
...
procedure Pn ( ... ) { • The language performs
...
} locking so that only one
process can be running
{ any monitor procedure at
initialization code
} a time.
}
6
Producer/Consumer using a Monitor
(pseudo code, not real C/Java)
Monitors in Java
A monitor can easily be implemented in Java:
A class in which all the methods are synchronized.
Guarantees mutual exclusion.
All instance and class variables need to be private or
protected.
7
Condition Synchronisation in Java
Monitor
data
Wait()
Notify()
class Semaphore {
private int value_;
Semaphore (int initial) {
value_=initial;
}
public synchronised down() {
while (value_==0) wait();
--value;
}
public synchronised up() {
++value_;
notify();
}
}
8
Condition Synchronisation in Java
Although Java has no condition variables, they can be
emulated via a loop:
Three solutions:
Semaphores may be stored in the kernel, and only accessed
through system calls.
Use shared-memory segments (available on Unix and
Windows).
Use a file.
9
Problems with Monitors
Message Passing
10
Producer/Consumer with Messages
#define N 100 #define N 100
11
Barriers
Use of a barrier
processes approaching a barrier
all processes but one blocked at barrier
last process arrives, all are let through
Summary
Many techniques for inter-process synchronization:
Semaphores:
low level, efficient, shared memory, hard to use right.
Monitors:
high level language construct, shared memory.
Message Passing:
asynchronous, low-level, no shared memory.
Next: Deadlocks.
12