0% found this document useful (0 votes)
42 views

L8 SemaphoreMonitor v2

This document discusses semaphores, monitors, and condition variables for synchronization in operating systems and concurrent programming. It begins with an overview of mutual exclusion and critical sections. It then covers semaphores, describing their initialization, P and V operations, and how they can be used to solve problems like the producer-consumer problem. Next, it introduces monitors as a higher-level abstraction that hides the complexity of mutual exclusion using condition variables and associated queues. It provides examples of using condition variables within a monitor for signaling between blocked threads.

Uploaded by

vmanthos
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views

L8 SemaphoreMonitor v2

This document discusses semaphores, monitors, and condition variables for synchronization in operating systems and concurrent programming. It begins with an overview of mutual exclusion and critical sections. It then covers semaphores, describing their initialization, P and V operations, and how they can be used to solve problems like the producer-consumer problem. Next, it introduces monitors as a higher-level abstraction that hides the complexity of mutual exclusion using condition variables and associated queues. It provides examples of using condition variables within a monitor for signaling between blocked threads.

Uploaded by

vmanthos
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 59

COS 318: Operating Systems

Semaphores, Monitors and


Condition Variables

Prof. Margaret Martonosi


Computer Science Department
Princeton University

http://www.cs.princeton.edu/courses/archive/fall11/cos318/
Today’s Topics
  Semaphores
  Monitors

  Mesa-style monitors

  Programming idiom

2
Mutual Exclusion and Critical Sections
  A critical section is a piece of code in which a process or
thread accesses a common (shared or global) resource.

  Mutual Exclusion algorithms are used to avoid the


simultaneous use of a common resource, such as a
global variable.

  In the buying milk example, what is the portion that


requires mutual exclusion?

3
Conditions for a good Mutex solution:

  No two processes may be simultaneously inside their


critical regions.
  No assumptions may be made about speeds or the
number of CPUs.
  No process running outside its critical region may block
other processes.
  No process should have to wait forever to enter its
critical region.

4
The Big Picture

OS codes and concurrent applications

High-Level
Mutex Semaphores Monitors Send/Recv
Atomic API

Low-Level Interrupt Other atomic


Load/store Test&Set
Atomic Ops disable/enable instructions

Interrupts CPU
Multiprocessors
(I/O, timer) scheduling

5
Semaphores (Dijkstra, 1965)
  Initialization
  Initialize a value atomically
  P (or Down or Wait) definition
  Atomic operation
  Wait for semaphore to become positive and then decrement
P(s){
while (s <= 0)
;
Analogy: Think about semaphore
s--; value as the number of empty
} chairs at a table…
  V (or Up or Signal) definition
  Atomic operation
  Increment semaphore by 1
V(s){ The atomicity and the waiting
s++;
}
can be implemented by either
busywaiting or blocking
solutions. 6
An aside on Dijkstra…
  Quite a personality…Avoided owning a computer for
several decades into his career…Won the 1972 Turing
Award…
  Created a series of numbered memos with his thoughts
on computing topics
  Now Archived at U. Texas:
  http://www.cs.utexas.edu/~EWD/
  Example: “A Tutorial on the Split Binary Semaphore”
•  http://www.cs.utexas.edu/~EWD/ewd07xx/EWD703.PDF
  Some are short proofs or papers, others are jokes or rants.
  Go-to statement considered harmful: Published in CACM
1968, also as EWD215…

7
Semaphores can be used for…
  Binary semaphores can provide mutual exclusion
(solution of critical section problem)
  Counting semaphores can represent a resource with
multiple instances (e.g. solving producer/consumer
problem)
  Signaling events (persistent events that stay
relevant even if nobody listening right now)
Classic Synchronization Problems
  There are a number of “classic” problems that represent
a class of synchronization situations
  Critical Section problem

  Producer/Consumer problem

  Reader/Writer problem

  5 Dining Philosophers

  Why? Once you know the “generic” solutions, you can


recognize other special cases in which to apply them
(e.g., this is just a version of the reader/writer problem)
Producer / Consumer
Producer: Consumer:
while(whatever) while(whatever)
{ {
locally generate item

get item from full buffer

fill empty buffer with item


use item
}
}
Producer / Consumer (With Counting
Semaphores)
Producer: Consumer:
while(whatever) while(whatever)
{ {
locally generate item
P(fullbuf);
P(emptybuf);
get item from full buffer

V(emptybuf);
fill empty buffer with item
V(fullbuf); use item
}
}
Semaphores: emptybuf initially N; fullbuf initially 0;
Producer Consumer (Bounded Buffer)
with Semaphores: More detail…
producer() { consumer() {
while (1) { while (1) {
produce an item P(fullBuf);
P(emptyBuf);
P(mutex);
P(mutex); take an item from buffer
put the item in buffer V(mutex);
V(mutex);
V(emptyBuf);
V(fullBuf); consume the item
} }
} }

  Init:
emptyCount = N; fullCount = 0; mutex = 1
  Are P(mutex)and V(mutex) necessary?
Example: Interrupt Handler
  A device thread works with an interrupt handler
  What to do with shared data?

  What if “m” is held by another thread or by itself?

Device thread Interrupt handler

... ...

?
Acquire(m); Acquire(m);
... ...

Release(m); Release(m);
... ...

13
Use Semaphore to Signal

Init(s,0);

Device thread Interrupted Thread


while (1) {
P(s); …
Acquire(m); Interrupt handler
... ... Interrupt
deal with interrupt V(s); …
... ...
Release(m);
}

14
Semaphores Are Not Always Convenient

  A shared queue has Enqueue and Dequeue:


Enqueue(q, item) Dequeue(q)
{ {
Acquire(mutex); Acquire(mutex);
put item into q; take an item from q;
Release(mutex); Release(mutex);
} return item;
}

  It is a consumer and producer problem


  Dequeue(q) should block until q is not empty
  Semaphores are difficult to use: orders are important
Today’s Topics
  Semaphores
  Monitors

  Mesa-style monitors

  Programming idiom

  Barriers

16
The Big Picture

OS codes and concurrent applications

High-Level
Mutex Semaphores Monitors Send/Recv
Atomic API

Low-Level Interrupt Other atomic


Load/store Test&Set
Atomic Ops disable/enable instructions

Interrupts CPU
Multiprocessors
(I/O, timer) scheduling

17
Monitor: Hide Mutual Exclusion

  Brinch-Hansen (73), Hoare (74)


  Procedures are mutual exclusive

Shared
data
Queue of waiting processes
trying to enter the monitor
...

procedures
Condition Variables in A Monitor

  Wait( condition ) Queues


associated
  Block on “condition” with x, y
  Signal( condition ) conditions
  Wakeup a blocked process x
y
on “condition”
Shared
data

...
Entry queue
procedures
Monitor Abstraction

  Encapsulates shared

notEmpty
entry queue
data and operations
with mutual exclusive monitor_lock
use of the object (an
associated lock).
enQ deQ
  Associated Condition
Variables with
init
operations of Wait shared data
and Signal.
conditions
Condition Variables

  We build the monitor abstraction out of a lock


(for the mutual exclusion) and a set of
associated condition variables.
  Wait on condition: releases lock held by
caller, caller goes to sleep on condition’s
queue.
When awakened, it must reacquire lock.
  Signal condition: wakes up one waiting
thread.
  Broadcast: wakes up all threads waiting on
this condition.
Monitor Abstraction

EnQ:{acquire (lock);
if (head == null)

notEmpty
entry queue
{head = item;
signal (lock, notEmpty);}
else tail->next = item; monitor_lock
tail = item;
release(lock);}
deQ:{acquire (lock); enQ deQ
if (head == null)
wait (lock, notEmpty);
init
item = head; shared data
if (tail == head) tail = null;
head=item->next;
conditions
release(lock);}
Monitor Abstraction

EnQ:{acquire (lock);
if (head == null)

notEmpty
entry queue
{head = item;
signal (lock, notEmpty);}
else tail->next = item; monitor_lock
tail = item;
release(lock);}
deQ:{acquire (lock); enQ deQ
if (head == null)
wait (lock, notEmpty);
init
item = head; shared data
if (tail == head) tail = null;
head=item->next;
conditions
release(lock);}
Monitor Abstraction

EnQ:{acquire (lock);
if (head == null)

notEmpty
entry queue
{head = item;
signal (lock, notEmpty);}
else tail->next = item; monitor_lock
tail = item;
release(lock);}
deQ:{acquire (lock); enQ deQ
if (head == null)
wait (lock, notEmpty);
init
item = head; shared data
if (tail == head) tail = null;
head=item->next;
conditions
release(lock);}
Monitor Abstraction

EnQ:{acquire (lock);
if (head == null)

notEmpty
entry queue
{head = item;
signal (lock, notEmpty);}
else tail->next = item; monitor_lock
tail = item;
release(lock);}
deQ:{acquire (lock); enQ deQ
if (head == null)
wait (lock, notEmpty);
init
item = head; shared data
if (tail == head) tail = null;
head=item->next;
conditions
release(lock);}
Monitor Abstraction

EnQ:{acquire (lock);
if (head == null)

notEmpty
entry queue
{head = item;
signal (lock, notEmpty);}
else tail->next = item; monitor_lock
tail = item;
release(lock);}
deQ:{acquire (lock); enQ deQ
if (head == null)
wait (lock, notEmpty);
init
item = head; shared data
if (tail == head) tail = null;
head=item->next;
conditions
release(lock);}
Monitor Abstraction

EnQ:{acquire (lock);
if (head == null)

notEmpty
entry queue
{head = item;
signal (lock, notEmpty);}
else tail->next = item; monitor_lock
tail = item;
release(lock);}
deQ:{acquire (lock); enQ deQ
while (head == null)
wait (lock, notEmpty);
init
item = head; shared data
if (tail == head) tail = null;
head=item->next;
conditions
release(lock);}
Producer-Consumer with Monitors

monitor ProdCons
condition full, empty;
procedure Producer
begin procedure Enter;
while true do begin
begin if (buffer is full)
produce an item wait(full);
ProdCons.Enter(); put item into buffer;
end; if (only one item)
end; signal(empty);
end;
procedure Consumer
begin procedure Remove;
while true do begin
begin if (buffer is empty)
ProdCons.Remove(); wait(empty);
consume an item; remove an item;
end; if (buffer was full)
end; signal(full);
end;
Options of the Signaler
  Run the signaled thread immediately and suspend the
current one (Hoare)
  If the signaler has other work to do, life is complex
  It is difficult to make sure there is nothing to do, because the
signal implementation is not aware of how it is used
  It is easy to prove things
  Exit the monitor (Hansen)
  Signal must be the last statement of a monitor procedure
  Continues its execution (Mesa)
  Easy to implement
  But, the condition may not be true when the awaken process
actually gets a chance to run

29
Today’s Topics
  Semaphores
  Monitors

  Mesa-style monitors

  Programming idiom

  Barriers

30
Mesa Style “Monitor” (Birrell’s Paper)
  Associate a condition variable with a mutex
  Wait( mutex, condition )
  Atomically unlock the mutex and enqueued on the condition
variable (block the thread)
  Re-lock the lock when it is awakened
  Signal( condition )
  No-op if there is no thread blocked on the condition variable
  Wake up at least one if there are threads blocked
  Broadcast( condition )
  Wake up all waiting threads
  Original Mesa paper
  B. Lampson and D. Redell. Experience with processes and
monitors in Mesa. Comm. ACM 23, 2 (feb 1980), pp 106-117.
Consumer-Producer with Mesa-Style Monitor

static count = 0;
static Cond full, empty;
static Mutex lock;

Enter(Item item) { Remove(Item item) {


Acquire(lock); Acquire(lock);
if (count==N) if (!count)
Wait(lock, full); Wait(lock, empty);
insert item into buffer remove item from buffer
count++; count--;
if (count==1) if (count==N-1)
Signal(empty); Signal(full);
Release(lock); Release(lock);
} }

Any issues with this?


32
Consumer-Producer with Mesa-Style Monitor

static count = 0;
static Cond full, empty;
static Mutex lock;

Enter(Item item) { Remove(Item item) {


Acquire(lock); Acquire(lock);
while (count==N) while (!count)
Wait(lock, full); Wait(lock, empty);
insert item into buffer remove item from buffer
count++; count--;
if (count==1) if (count==N-1)
Signal(empty); Signal(full);
Release(lock); Release(lock);
} }

33
Today’s Topics
  Semaphores
  Monitors

  Mesa-style monitors

  Programming idiom

  Barriers

34
The Programming Idiom
  Waiting for a resource   Make a resource available

Acquire( mutex ); Acquire( mutex );


while ( no resource ) ...
wait( mutex, cond ); (make resource available)
... ...
(use the resource) Signal( cond );
... /* or Broadcast( cond );
Release( mutex); Release( mutex);

35
Revisit the Motivation Example

Enqueue(Queue q, Item GetItem(Queue q) {


Item item) { Item item;

Acquire(lock); Acquire( lock );


while ( q is empty )
insert an item to q; Wait( lock, Empty);

Signal(Empty); remove an item;


Release(lock);
} Release( lock );
return item;
}

  Does this work?


Condition Variables Primitives
  Wait( mutex, cond )   Signal( cond )
  Enter the critical section   Enter the critical section
(min busy wait) (min busy wait)
  Release mutex   Wake up a TCB in cond’s
  Save state to TCB, mark queue
as blocked   Exit the critical section
  Put my TCB on cond’s
queue
  Exit the critical section
  Call the scheduler

  Waking up:
•  Acquire mutex
•  Resume
37
More on Mesa-Style Monitor
  Signaler continues execution
  Waiters simply put on ready queue, with no special
priority
  Must reevaluate the condition
  No constraints on when the waiting thread/process must
run after a “signal”
  Simple to introduce a broadcast: wake up all

  No constrains on signaler
  Can execute after signal call (Hansen’s cannot)
  Do not need to relinquish control to awaken thread/process
Evolution of Monitors
  Brinch-Hansen (73) and Hoare Monitor (74)
  Concept, but no implementation
  Requires Signal to be the last statement (Hansen)
  Requires relinquishing CPU to signaler (Hoare)
  Mesa Language (77)
  Monitor in language, but signaler keeps mutex and CPU
  Waiter simply put on ready queue, with no special priority
  Modula-2+ (84) and Modula-3 (88)
  Explicit LOCK primitive
  Mesa-style monitor
  Pthreads (95)
  Started standard effort around 1989
  Defined by ANSI/IEEE POSIX 1003.1 Runtime library
  Java threads
  Use ‘synchronized’ primitive for mutual exclusion
  Wait() and notify() use implicit per-class condition variable
Today’s Topics
  Semaphores
  Monitors

  Mesa-style monitors

  Programming idiom

  Barriers

40
Example: A Simple Barrier
  Thread A and Thread B
want to meet at a Thread A Thread B
particular point and then
go on

  How would you program


this with a monitor?

41
Using Semaphores as A Barrier
  Use two semaphore?
init(s1, 0);
init(s2, 0);

Thread A Thread B
… …
V(s1); V(s2);
P(s2); P(s1);
… …

  What about more than two threads?

42
Barrier Primitive
  Functions
  Take a barrier variable
  Broadcast to n-1 threads Thread 1 Thread n
… ... …
  When barrier variable has Barrier(b); Barrier(b);
reached n, go forward … …
  Hardware support on
some parallel machines

Barrier
variable

43
Equivalence
  Semaphores
  Good for signaling
  Not good for mutex because it is easy to introduce a bug

  Monitors
  Good for scheduling and mutex
  Maybe costly for a simple signaling

44
Summary
  Semaphores
  Monitors

  Mesa-style monitor and its idiom

  Barriers

45
5 Dining Philosophers

Philosopher 0 while(food available)


{pick up 2 adj. forks;
Philosopher 4 eat;
put down forks;
think awhile;
}

Philosopher 1
Philosopher 3

Philosopher 2
Template for Philosopher

while (food available)


{ /*pick up forks*/

eat;
/*put down forks*/

think awhile;
}
Naive Solution

while (food available)


{ /*pick up forks*/
P(fork[left(me)]);
P(fork[right(me)]);

eat;
/*put down forks*/
V(fork[left(me)]);
V(fork[right(me)]);

think awhile;
} Does this work?
Simplest Example of Deadlock

Thread 0 Interleavin Thread 1


g
P(R1) P(R2)
P(R2) P(R1) P(R1)
V(R1) P(R2) V(R2)
V(R2) P(R1) V(R1)
waits
R1 and R2 initially 1 (binary
P(R2)semaphore)
waits
Conditions for Deadlock

  Mutually exclusive use of resources


  Binary semaphores R1 and R2

  Circular waiting
  Thread 0 waits for Thread 1 to V(R2) and
Thread 1 waits for Thread 0 to V(R1)
  Hold and wait
  Holding either R1 or R2 while waiting on other

  No pre-emption
  Neither R1 nor R2 are removed from their respective holding
Threads.
Philosophy 101
(or why 5DP is interesting)

  How to eat with your Fellows without causing


Deadlock.
  Circular arguments (the circular wait condition)

  Not giving up on firmly held things (no preemption)

  Infinite patience with Half-baked schemes (hold


some & wait for more)
  Why Starvation exists and what we can do about it.
Dealing with Deadlock

It can be prevented by breaking one of the


prerequisite conditions:
  Mutually exclusive use of resources
  Example: Allowing shared access to read-only
files (readers/writers problem)
  circular waiting
  Example: Define an ordering on resources and
acquire them in order
  hold and wait
  no pre-emption
Circular Wait Condition
while (food available)
{ if (me == 0) {P(fork[left(me)]); P(fork[right(me)]);}
else {(P(fork[right(me)]); P(fork[left(me)]); }
eat;
V(fork[left(me)]); V(fork[right(me)]);

think awhile;
}
Hold and Wait Condition

while (food available)


{ P(mutex);
while (forks [me] != 2)
{blocking[me] = true; V(mutex); P(sleepy[me]); P(mutex);}
forks [leftneighbor(me)] --; forks [rightneighbor(me)]--;
V(mutex):
eat;
P(mutex); forks [leftneighbor(me)] ++; forks [rightneighbor(me)]++;
if (blocking[leftneighbor(me)]) {blocking [leftneighbor(me)] = false; V
(sleepy[leftneighbor(me)]); }
if (blocking[rightneighbor(me)]) {blocking[rightneighbor(me)] = false; V
(sleepy[rightneighbor(me)]); } V(mutex);
think awhile;
}
Starvation

The difference between deadlock and starvation is


subtle:
  Once a set of processes are deadlocked, there is
no future execution sequence that can get them
out of it.
  In starvation, there does exist some execution
sequence that is favorable to the starving
process although there is no guarantee it will
ever occur.
  Rollback and Retry solutions are prone to
starvation.
  Continuous arrival of higher priority processes is
another common starvation situation.
5DP - Monitor Style

Boolean eating [5];


Lock forkMutex;
Condition forksAvail;

void PickupForks (int i) {


void PutdownForks (int i) {
forkMutex.Acquire( );
forkMutex.Acquire( );
while ( eating[(i-1)%5] || eating
[(i+1)%5] ) eating[i] = false;
forksAvail.Wait(&forkMutex); forksAvail.Broadcast
eating[i] = true; (&forkMutex);
forkMutex.Release( ); forkMutex.Release( );
} }
What about this?

while (food available)


{ forkMutex.Acquire( );
while (forks [me] != 2) {blocking[me]=true;
forkMutex.Release( ); sleep( ); forkMutex.Acquire( );}
forks [leftneighbor(me)]--; forks [rightneighbor(me)]--;
forkMutex.Release( ):
eat;
forkMutex.Acquire( );
forks[leftneighbor(me)] ++; forks [rightneighbor(me)]++;
if (blocking[leftneighbor(me)] || blocking[rightneighbor(me)])
wakeup ( ); forkMutex.Release( );
think awhile;
}
Classic Synchronization Problems
  There are a number of “classic” problems that represent
a class of synchronization situations
  Critical Section problem

  Producer/Consumer problem

  Reader/Writer problem

  5 Dining Philosophers

  Why? Once you know the “generic” solutions, you can


recognize other special cases in which to apply them
(e.g., this is just a version of the reader/writer problem)
Readers/Writers Problem
Synchronizing access to a file or data record in a database
such that any number of threads requesting read-only
access are allowed but only one thread requesting write
access is allowed, excluding all readers.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy