36
3. Higher-Level Synchronization 3.1 Shared Memory Methods Monitors Protected Types 3.2 Distributed Synchronization/Comm. Message-Based Communication Procedure-Based Communication Distributed Mutual Exclusion 3.3 Other Classical Problems The Readers/Writers Problem The Dining Philosophers Problem The Elevator Algorithm Operating Systems 1

3. Higher-Level Synchronization 3.1 Shared Memory Methods –Monitors –Protected Types 3.2 Distributed Synchronization/Comm. –Message-Based Communication

Embed Size (px)

Citation preview

3. Higher-Level Synchronization3.1 Shared Memory Methods

– Monitors – Protected Types

3.2 Distributed Synchronization/Comm.– Message-Based Communication – Procedure-Based Communication – Distributed Mutual Exclusion

3.3 Other Classical Problems– The Readers/Writers Problem– The Dining Philosophers Problem – The Elevator Algorithm

Operating Systems 1

Motivation• Semaphores are powerful but low-level

abstractions• Programming with them is highly error prone• Such programs are difficult to design, debug, and

maintain

– Not usable in distributed memory systems

• Need higher-level primitives – Based on semaphores or messages

Operating Systems 2

Monitors• Follow the principles of abstract data types

(object-oriented programming):– A data object is manipulated only by a set of

predefined operations• A monitor consists of:

– A collection of data representing the state of the resource controlled by the monitor, and

– Procedures/functions to manipulate the data

Operating Systems 3

Monitors• Implementation must guarantee:

1. Resource is accessible by only monitor procedures

2. Monitor procedures are mutually exclusive• For coordination, monitor provides

– “condition variable” c • not a conventional variable, has no value, only a name

chosen by programmer • Each c has a waiting queue associated

– c.wait• Calling process is blocked and placed on queue

– c.signal• Calling process wakes up waiting process (if any)

Operating Systems 4

Monitors• Example: process p1 needs to wait until a variable

X becomes positive before it can proceed

• p1 steps out to wait on queue associated with condition variable X_is_positive

Operating Systems 5

Monitors

• process p1 may reenter the monitor, however …

• Another process may execute X_is_positive.signal to wake up p1 when X becomes positive

Operating Systems 6

Monitors• Design Issue:

– After c.signal, there are 2 ready processes:• The calling process that did the c.signal• The waiting process that the c.signal woke

up– Which should continue?

(Only one can be executing inside the monitor!)

Two different approaches– Hoare monitors– Mesa-style monitors

Operating Systems 7

Hoare Monitors• Introduced by Tony Hoare in a 1974

http://wikipedia.org/wiki/C._A._R._Hoare

• First implemented by Per Brinch Hansen in Concurrent Pascal

http://wikipedia.org/wiki/Per_Brinch_Hansen

• Approach taken by Hoare monitor:– After c.signal,

• Awakened process continues• Calling process is suspended, and placed

on high-priority queue

Operating Systems 8

Hoare Monitors• Effect of c.signal

Operating Systems 9

urgent

p1 reenters

• Signaling process has the highest priority– It reenters as soon as p1 terminates

Bounded buffer problemmonitor BoundedBuffer { char buffer[n]; int nextin=0, nextout=0, fullCount=0; condition notempty, notfull;

deposit(char data) { if (fullCount==n) notfull.wait;

buffer[nextin] = data; nextin = (nextin+1) % n; fullCount = fullCount+1; notempty.signal; }

remove(char data) { if (fullCount==0) notempty.wait; data = buffer[nextout]; nextout = (nextout+1) % n; fullCount = fullCount - 1; notfull.signal; } }

Operating Systems 10

Priority waits• Original Hoare monitor signal resumes longest waiting

process (i.e., queue is a FIFO queue)– May lead to unnecessary wake-ups

• Solution: Priority Waits– Every wait operation specifies a priority p

c.wait(p)– Waiting processes are kept sorted by p– Smallest p = highest priority

• Reason: p frequently represents time• Earlier events (smaller p) must be processed first

– c.signal wakes up highest-priority process (lowest p)

Operating Systems 11

Example: alarm clock• A monitor (AlarmClock) maintains the current time value• Time is advanced by periodic calls by hardware• A processes can go to sleep by calling AlarmClock.wakeMe(n)

monitor AlarmClock { int now=0; condition wakeup;

tick() { /*invoked by hardware*/ now = now + 1; wakeup.signal; }

wakeMe(int n) { int alarm; alarm = now + n; while (now<alarm) wakeup.wait(alarm); wakeup.signal; } }

Operating Systems 12

Example: alarm clock• Why do we need the last wakeup.signal in wakeMe?

• tick only wakes up one process

• If there are multiple processes with same alarm time, all must be awakened

– tick wakes up the first process

– the first process wakes up the second process, etc.

• Do we really need priority waits?

• Not for correctness but for efficiency:

– Without priority waits, all processes would need to wake up to check their alarm settings

Operating Systems 13

Mesa-style monitors• After issuing c.signal, calling process continues executing

• Problem: Condition cannot be guaranteed after wakeup– Assume that p1 and p2 are waiting for some condition c

– Caller could satisfying c and wake up both processes– Assume p1 starts and makes the condition false again

– When p2 resumes, c is not guaranteed to be true

• Solution: process must retest c after wakeup

instead of: if (!condition) c.wait

use: while (!condition) c.wait• This form of signal is sometimes called notify

Operating Systems 14

Protected types• Introduced in programming language Ada (1995)

• Equivalent to special case of monitor where

– c.wait is the first operation of a procedure

– c.signal is the last operation

• wait/signal are combined into a when(cond) clause

– Procedure executes only when the condition is true

– when(cond) guards access to the procedure (instead of: if (!cond) c.wait; )

– When some other procedure makes cond true and terminates, it automatically enables the corresponding when clauses (instead of c.signal)

Operating Systems 17

Example: Bounded Bufferdeposit(char c) when (fullCount < n) { buffer[nextin] = c; nextin = (nextin + 1) % n; fullCount = fullCount + 1; } remove(char c) when (fullCount > 0) { c = buffer[nextout]; nextout = (nextout + 1) % n; fullCount = fullCount - 1; }

Operating Systems 18

Distributed Synchronization• Semaphore-based primitive requires shared memory• For distributed memory:

– send(p,m)• Send message m to process p

– receive(q,m)• Receive message from process q in variable m

• Semantics of send and receive vary significantly in different systems:– Does sender wait for message to be accepted?– Does receiver wait if there is no message?– Does sender name exactly one receiver?– Does receiver name exactly one sender?

Operating Systems 19

Types of send/receive

Operating Systems 20

send blocking nonblockingexplicitnaming

send m to rwait until accepted

send m to r

implicitnaming

broadcast mwait until accepted

broadcast m

receive blocking nonblockingexplicitnaming

wait for messagefrom s

if there is a message from s,receive it; else proceed

implicitnaming

wait for messagefrom any sender

if there is a message from anysender, receive it; else proceed

Procedure-Based Communication• Send/Receive are low level (like P/V)

• Typical interaction: Client-Server– Send Request, Receive Result

Make this into a single higher-level primitive

• RPC (Remote Procedure Call) or Rendezvous

– Caller invokes procedure on remote machine

– Remote machine performs operation and returns result

– Similar to regular procedure call, with some differences

• Parameters cannot contain pointers or shared references

• Partial failure semantics

Operating Systems 30

RPC• Caller issues:

result = f(params)

• This is translated into:

Operating Systems 31

Calling Process

... send(server,f,params); receive(server,result); ...

Server Process

process RP_server { while (1) { receive(caller,f,params); result=f(params); send(caller,result); } }

Rendezvous• A more general procedure-based mechanism

• Introduced as part of programming language Ada

• With RPC: Called process p is part of a dedicated server

• With Rendezvous:

– p is part of an arbitrary (user) process

– p maintains state between calls

– p may accept/delay/reject call

– Setup is symmetrical: Any process may be a client or a server

Operating Systems 32

Rendezvous• Caller: Similar syntax/semantics to RPC

q.f(param)

where q is the called process (server)

• Server: Must indicate willingness to accept:

accept f(param) S

• Rendezvous:– both processes wait for each other– then server executes S (rendezvous)– both processes continue in parallel

• (Rendezvous = meeting/date in French )

Operating Systems 33

Rendezvous

Operating Systems 34

Selective Receive• Permit server to wait for multiple asynchronous calls

– Select statement encloses multiple accepts– Each accept may be guarded using a when clause

Operating Systems 35

select { [when B1:] accept E1(…) S1; or [when B2:] accept E2(…) S2; or … [when Bn:] accept En(…) Sn; [else R] }

• Accept and process all enabled calls• If there is no such call, execute else clause

– If no else clause, error

Example: Bounded Bufferprocess BoundedBuffer { while(1) { select { when (fullCount < n): accept deposit(char c) { buffer[nextin] = c; nextin = (nextin + 1) % n; fullCount = fullCount + 1; } or when (fullCount > 0): accept remove(char c) { c = buffer[nextout]; nextout = (nextout + 1) % n; fullCount = fullCount - 1; } }}}

Operating Systems 36

Readers/Writers Problem• Extension of basic Critical Section problem• Two types of processes entering a CS:

Readers (R) and Writers (W)• CS may only contain

– A single W process (and no R processes); or– Any number of R processes (and no W processes).

• A good solution should:– Satisfy the mutual exclusion conditions– Maximize number of simultaneous R processes in CS– Prevent starvation of either process type

Operating Systems 42

Readers/Writers Problem• Two possible approaches:

– R has priority over W:

when at least one R is in CS, new R’s may enter

when W exits, R’s have priority

– W has priority over R:

when a W is waiting, no new R processes may enter

when last R exits, W enters

when W exits, W’s have priority

• Both approaches satisfy mutual exclusion and simultaneous R access, but

• Both also lead to starvation of W or ROperating Systems 43

44Operating Systems 44

Readers/Writers Problem• Solution that prevents starvation of either R or W:

– R’s are in CS:• a new R cannot enter if a W is waiting• the arrival of W stops the stream of R’s• when last R exits, W enters• W’s cannot starve

– W is in CS:• when W leaves, all R’s that have arrived up to

that point may enter

(even those that arrived after the next W!)• R’s cannot starve

Solution using monitormonitor Readers_Writers { int readCount=0,writing=0; condition OK_R, OK_W;

start_read() { if (writing || !empty(OK_W)) OK_R.wait; readCount = readCount + 1; OK_R.signal; } end_read() { readCount = readCount - 1; if (readCount == 0) OK_W.signal; }

start_write() { if ((readCount !=0)||writing) OK_W.wait; writing = 1; }

end_write() { writing = 0; if (!empty(OK_R)) OK_R.signal; else OK_W.signal; } }

Operating Systems 45

Dining philosophers Problem• Each philosopher alternates between eating

and thinking• Each philosopher needs both forks to eat• Requirements

– Prevent deadlock– Guarantee fairness:

no philosopher must starve– Guarantee concurrency:

non-neighbors may eat at the same time

Operating Systems 46

Dining philosophers problem•Basic structure for each philosopher

p(i) : while (1) { think(i);

grab_forks(i);eat(i);return_forks(i); }

• Each fork is a semaphore; grab=P(f[i]), return=V(f[i])• Assume each philosopher grabs (and returns) left fork first

grab_forks(i): { P(f[i]); P(f[i+1]) }

return_forks(i): { V(f[i]); V(f[i+1]) }

•Problem: May lead to deadlock –all grab left fork simultaneously, wait for right fork

Operating Systems 47

Dining Philosophers• Solutions to avoid deadlock

1. Use a counter:At most n–1 philosophers may attempt to grab forks

2. One philosopher requests forks in reverse order, e.g.,

grab_forks(1): { P(f [2]); P(f [1]) }• Both violate concurrency requirement:

– While P(1) is eating others could be blocked in a chain

Operating Systems 48

CompSci 143A 4949

Dining PhilosophersSolution that avoids deadlock and provides concurrency:

• Divide philosophers into two groups

• One group tries to grab left fork first, the other right fork

• For example: – Odd-numbered philosophers (1,3,5) grab left fork first– Even-numbered philosophers (2,4) grab right fork first

• Pairs of neighbors compete with each other, no chain

Elevator Algorithm• Loosely simulates an elevator (used for disk scheduling)• Organization of elevator

– n floors– Elevator can be called to floor i: request(i)– After elevator services a floor, it is released: released()

• Elevator scheduling policy– When elevator is moving up, it services all requests at

or above current position; then it reverses direction– When elevator is moving down, it services all requests

at or below current position; then it reverses direction

Operating Systems 50

Elevator algorithm• Implementation as a monitor

– Two procedures: request(i) and release()– When elevator is busy (moving or servicing a floor), request

must wait in one of two queues: upsweep or downsweep– Elevator services upsweep when moving up and

downsweep when moving down– Request must place itself in correct queue:

• If current position < destination, wait in upsweep• If current position > destination wait in downsweep• If current position = destination wait in upsweep or

downsweep depending on current direction

Operating Systems 51

Elevator algorithmMonitor elevator { int dir=1, pos=1, busy=0; cond upsweep, downsweep; request(int dest) { if (busy) { if (pos < dest) || ( (pos == dest) && (dir == up) ) ) upsweep.wait(dest); else downsweep.wait(-dest);} busy = 1; pos = dest; }

Operating Systems 52

release() { busy = 0; if (dir==up) if (!empty(upsweep)) upsweep.signal; else { dir = down; downsweep.signal; } else /*dir==down*/ if (!empty(downsweep)) downsweep.signal; else { dir = up; upsweep.signal; } } }