Title: Outline for 1/9/98
12-Dining Puppies Mutex Failure
2Outline for Today
- Objective
- Reader-writer problem
- Message Passing
- Administrative details
3Readers/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.
4Template for Readers/Writers
- Reader()
- while (true)
-
- read
-
- Writer()
- while (true)
-
- write
-
-
/request r access/
/request w access/
/release r access/
/release w access/
5Template for Readers/Writers
- Reader()
- while (true)
-
- read
-
- Writer()
- while (true)
-
- write
-
-
fd open(foo, 0)
fd open(foo, 1)
close(fd)
close(fd)
6Template for Readers/Writers
- Reader()
- while (true)
-
- read
-
- Writer()
- while (true)
-
- write
-
-
startRead()
startWrite()
endRead()
endWrite()
7R/W - Monitor Style
- Boolean busy false
- int numReaders 0
- Lock filesMutex
- Condition OKtoWrite, OKtoRead
- void startRead ()
- filesMutex.Acquire( )
- while ( busy )
- OKtoRead.Wait(filesMutex)
- numReaders
- filesMutex.Release( )
- void endRead ()
- filesMutex.Acquire( )
- numReaders--
- if (numReaders 0)
- OKtoWrite.Signal(filesMutex)
- filesMutex.Release( )
- void startWrite()
- filesMutex.Acquire( )
- while (busy numReaders ! 0) OKtoWrite.Wait(
filesMutex) - busy true
- filesMutex.Release( )
- void endWrite()
- filesMutex.Acquire( )
- busy false
- OKtoRead.Broadcast(filesMutex)
OKtoWrite.Signal(filesMutex) - filesMutex.Release( )
8Guidelines for Choosing Lock Granularity
- 1. Keep critical sections short. Push
noncritical statements outside of critical
sections to reduce contention. - 2. Limit lock overhead. Keep to a minimum the
number of times mutexes are acquired and
released. - Note tradeoff between contention and lock
overhead. - 3. Use as few mutexes as possible, but no fewer.
- Choose lock scope carefully if the operations on
two different data structures can be separated,
it may be more efficient to synchronize those
structures with separate locks. - Add new locks only as needed to reduce
contention. Correctness first, performance
second!
9Semaphore Solution
-
- int readCount 0
- semaphore mutex 1
- semaphore writeBlock 1
10- Reader()
- while (TRUE)
- other stuff
- P(mutex)
- readCount readCount 1
- if(readCount 1)
- P(writeBlock)
- V(mutex)
- access resource
- P(mutex)
- readCount readCount -1
- if(readCount 0)
- V(writeBlock)
- V(mutex)
- Writer()
- while(TRUE)
- other stuff
- P(writeBlock)
- access resource
- V(writeBlock)
-
11Attempt at Writer Priority
-
- int readCount 0, writeCount 0
- semaphore mutex1 1, mutex2 1
- semaphore readBlock 1
- semaphore writeBlock 1
12- Reader()
- while (TRUE)
- other stuff
- P(readBlock)
- P(mutex1)
- readCount readCount 1
- if(readCount 1)
- P(writeBlock)
- V(mutex1)
- V(readBlock)
- access resource
- P(mutex1)
- readCount readCount -1
- if(readCount 0)
- V(writeBlock)
- V(mutex1)
- Writer()
- while(TRUE)
- other stuff
- P(mutex2)
- writeCount writeCount 1
- if (writeCount 1)
- P(readBlock)
- V(mutex2)
- P(writeBlock)
- access resource
- V(writeBlock)
- P(mutex2)
- writeCount - writeCount - 1
- if (writeCount 0)
- V(readBlock)
- V(mutex2)
-
13- Reader()
- while (TRUE)
- other stuff
- P(readBlock)
- P(mutex1)
- readCount readCount 1
- if(readCount 1)
- P(writeBlock)
- V(mutex1)
- V(readBlock)
- access resource
- P(mutex1)
- readCount readCount -1
- if(readCount 0)
- V(writeBlock)
- V(mutex1)
- Writer()
- while(TRUE)
- other stuff
- P(mutex2)
- writeCount writeCount 1
- if (writeCount 1)
- P(readBlock)
- V(mutex2)
- P(writeBlock)
- access resource
- V(writeBlock)
- P(mutex2)
- writeCount - writeCount - 1
- if (writeCount 0)
- V(readBlock)
- V(mutex2)
-
14- Reader()
- while (TRUE)
- other stuff
- P(writePending)
- P(readBlock)
- P(mutex1)
- readCount readCount 1
- if(readCount 1)
- P(writeBlock)
- V(mutex1) V(readBlock)
- V(writePending)
- access resource
- P(mutex1)
- readCount readCount -1
- if(readCount 0)
- V(writeBlock)
- V(mutex1)
- Writer()
- while(TRUE)
- other stuff
- P(mutex2)
- writeCount writeCount 1
- if (writeCount 1)
- P(readBlock)
- V(mutex2)
- P(writeBlock)
- access resource
- V(writeBlock)
- P(mutex2)
- writeCount - writeCount - 1
- if (writeCount 0)
- V(readBlock)
- V(mutex2)
-
15- Reader()
- while (TRUE)
- other stuff
- P(writePending)
- P(readBlock)
- P(mutex1)
- readCount readCount 1
- if(readCount 1)
- P(writeBlock)
- V(mutex1) V(readBlock)
- V(writePending)
- access resource
- P(mutex1)
- readCount readCount -1
- if(readCount 0)
- V(writeBlock)
- V(mutex1)
- Writer()
- while(TRUE)
- other stuff
- P(mutex2)
- writeCount writeCount 1
- if (writeCount 1)
- P(readBlock)
- V(mutex2)
- P(writeBlock)
- access resource
- V(writeBlock)
- P(mutex2)
- writeCount - writeCount - 1
- if (writeCount 0)
- V(readBlock)
- V(mutex2)
-
Assumptions about semaphore semantics?
16- Reader()
- while (TRUE)
- other stuff
- P(writePending)
- P(readBlock)
- P(mutex1)
- readCount readCount 1
- if(readCount 1)
- P(writeBlock)
- V(mutex1) V(readBlock)
- V(writePending)
- access resource
- P(mutex1)
- readCount readCount -1
- if(readCount 0)
- V(writeBlock)
- V(mutex1)
- Writer()
- while(TRUE)
- other stuff
- P(mutex2)
- writeCount writeCount 1
- if (writeCount 1)
- P(readBlock)
- V(mutex2)
- P(writeBlock)
- access resource
- V(writeBlock)
- P(mutex2)
- writeCount - writeCount - 1
- if (writeCount 0)
- V(readBlock)
- V(mutex2)
-
Assume the writePending semaphore was omitted.
What would happen?
17- Assume the writePending semaphore was omitted in
the solution just given. What would happen?
This is supposed to give writers priority.
However, consider the following sequence Reader
1 arrives, executes thro P(readBlock) Reader 1
executes P(mutex1) Writer 1 arrives, waits at
P(readBlock) Reader 2 arrives, waits at
P(readBlock) Reader 1 executes V(mutex1) then
V(readBlock) Reader 2 may now proceedwrong
18Linux Reader/Writer Spinlocks
- Class of reader/writer problems
- Multiple readers OK
- Mutual exclusion for writers
- No upgrade from reader lock to writer lock
- Favors readers starvation of writers possible
- rwlock_t
- read_lock,read_unlock
- read_lock_irq // also unlock
- read_lock_irqsave
- read_unlock_irqrestore
- write_lock,write_unlock
- //_irq,_irqsave,_irqrestore
- write_trylock
- rw_is_locked
19Linux Reader/Writer Semaphores
- All reader / writer semaphores are mutexes (usage
count 1) - Multiple readers, solo writer
- Uninterruptible sleep
- Possible to downgrade writer to reader
- down_read
- down_write
- up_read
- up_write
- downgrade_writer
- down_read_trylock
- down_write_trylock
20Message-Passing
21Interprocess Communication - Messages
- Assume no explicit sharing of data elements in
the address spaces of processes wishing to
cooperate/communicate. - Essence of message-passing is copying (although
implementations may avoid actual copies whenever
possible). - Problem-solving with messages - has a feel of
more active involvement by participants.
22Issues
- System calls for sending and receiving messages
with the OS(s) acting as courier. - Variations on exact semantics of primitives and
in the definition of what comprises a message. - Naming - direct (to/from pids), indirect (to
distinct objects - e.g., mailboxes, ports,
sockets) - How do unrelated processes find each other?
- Buffering - capacity and blocking semantics.
- Guarantees - in-order delivery? no lost messages?
23Send and Receive
24UNIX Sockets for Client/ Server Message Passing
- Server
- 1. Create a named socketsyscallssfd
socket()bind (sfd, ptr,len) - 2. Listen for clientslisten(sfd,numpend)
- 4. Connection made and continue
listeningcfdaccept(sfd, ) - 5. Exchange datawrite(cfd, )
- 6. Done close(cfd)
- 7. Really done close(sfd)
- Client
- 3. Create unnamed socket ask for
connectionsyscallscfdsocket()errconnect(cfd
, ptr, ) - 5. Exchange data read(cfd, )
- 6. Done close(cfd)
name
name
255 DP Direct Send/Receive Message Passing
Between Philosophers
Forkplease?
Philosopher 0(thinking)
Philosopher 4
Philosopher 1
Philosopher 3 (eating)
Philosopher 2
26Umm. Oh yeah.
Philosopher 0(thinking)
Philosopher 4
Philosopher 1
Philosopher 3 (eating)
Philosopher 2
27Forkplease?
Philosopher 0(thinking)
Philosopher 4
Philosopher 1
Philosopher 3 (eating)
Philosopher 2
28Forkplease?
Philosopher 0(thinking)
Philosopher 4
Ill ignore that request until Im done
Philosopher 1
Philosopher 3 (eating)
Philosopher 2
29Philosopher 0(thinking)
Philosopher 4
Forkplease?
Philosopher 1
Philosopher 3 (eating)
Forkplease?
Philosopher 2
30Client / Server
Start here
server-gt
31Example Time Service
32Example Time Service via Messages
33Client / Server with Threads
34Hiding Message-Passing RPC
35Remote Procedure Call - RPC
- Looks like a nice familiar procedure call
P1
P0
Receive
result foo(param)
36Remote Procedure Call - RPC
- Looks like a nice familiar procedure call
P1
P0
please do foo for P0 with param
Receive
result foo(param)
blocked here
37Remote Procedure Call - RPC
- Looks like a nice familiar procedure call
P1
P0
please do foo for P0 with param
Receive
result foo(param)
r foo(param) // actual call
blocked here
38Remote Procedure Call - RPC
- Looks like a nice familiar procedure call
P1
P0
Receive
result foo(param)
r foo(param) // actual call
blocked here
Reply
returning r to P0
39Remote Procedure Call - RPC
- Looks like a nice familiar procedure call
P1
P0
Receive
result foo(param)
r foo(param) // actual call
Reply
returning r to P0
40Remote Procedure Call - RPC
- Looks like a nice familiar procedure call
P1
P0
Receive
result foo(param)
r foo(param) // actual call
Reply
415DP via RPC with Fork Manager
- Looks like a nice familiar procedure call
Fork Server
Philosopher0
Receive
result PickupForks (0)
r proc(param) // explicit queuing when
necessary
Reply
42Example Time Service via RPC
43Whats Really Going On
44RPC Issues