Revisiting monitors
Readers/writers problem
Another classic synchronisation problem
Two kinds of threads share access to a database
Readers examine the contents
Multiple readers allowed concurrently
Writers examine and modify
A writer must have mutex
Database is globally accessible
- It cannot be internal to the monitor, i.e., the critical section!
The monitor only encapsulate the access protocol
First attempt
Monitor, Reader, Writer, and top-level
Code skeleton
public class RW { private final Lock lock = new ReentrantLock(); private final Condition okToRead = lock.newCondition(); private final Condition okToWrite = lock.newCondition(); private int readers = 0 ; private int writers = 0 ; public RW(){} public void startRead() { lock.lock() ; // code readers++ ; lock.unlock() ; } public void startWrite() { lock.lock() ; // code writers = 1 ; lock.unlock() ; } public void endRead() { lock.lock() ; readers-- ; //code lock.unlock() ; } public void endWrite() { lock.lock() ; writers = 0 //code lock.unlock() ; } }
When starting reading or writing
public void startRead() { lock.lock() ; while (writer == 1) okToRead.await() ; // code readers++ ; lock.unlock() ; } public void startWrite() { lock.lock() ; while (readers > 0 || writer == 1) okToWrite.await() ; // code writers = 1 ; lock.unlock() ; }
When finishing reading and writing
public void endRead() { lock.lock() ; readers-- ; if (readers == 0) okToWrite.signal() ; lock.unlock() ; } public void endWrite() { lock.lock() ; writers = 0 okToWrite.signal() ; okToRead.signalAll() ; lock.unlock() ; }
Why not signaling
okToRead
inendRead
?- There cannot be a blocked reading thread when running
endRead
. Readers only block due to one writer and that writer will wake up all the *readers!
- There cannot be a blocked reading thread when running
Analysis
Does it work?
Yes! It fulfills the requirements given in the first part of the lecture (mutex for writers, several readers when no writers running, etc.).
What about fairness?
Fairness
What about a continues flow of readers?
Fairness considerations
Suitable policy?
No new readers when a writer is waiting
Change turns in some way
Fairness often requires more book-keeping
Depends highly on platform
Java
signalAll()
might be inevitable for condition rechecking
Second Attempt
Monitor, Reader, Writer, and top-level program
Book-keeping the threads interested on reading / writing
private int wreaders = 0 ; private int wwriters = 0 ;
endWrite
public void endWrite() { lock.lock() ; writer = 0 ; okToRead.signalAll() ; okToWrite.signal() ; lock.unlock() ; }
endRead
(as before)public void endRead() { lock.lock() ; readers-- ; if (readers == 0) okToWrite.signal() ; lock.unlock() ; }
startWrite
public void startWrite() throws InterruptedException { lock.lock() ; wwriters++ ; while (readers > 0 || writer == 1) okToWrite.await() ; wwriters-- ; writer = 1 ; lock.unlock() ; }
startRead
public void startRead() throws InterruptedException { lock.lock() ; wreaders++ ; while (writer == 1 || wwriters > 0) okToRead.await() ; wreaders-- ; readers++ ; lock.unlock() ; }
Analysis
What happens with a writer with a continuous flow of readers?
- The writer will eventually run! (see
startRead
andendRead
)
- The writer will eventually run! (see
What happens with a reader with a continuous flow of writers?
- The readers will eventually run! (see
endWrite
)
- The readers will eventually run! (see
Is it fair?
Well, it is not an easy question to answer.
It is not a fair solution!
This is due to the signal and continue discipline
Imagine a reader thread waiting 10 years to proceed and just before that the chance is taken by another one waiting for 10 seconds. The pattern can be seen here
What else could we do?
More book-keeping
We will not do it here and we will be satisfied with this almost fair solution
Resource allocation problem
A controller controls access to copies of some resource
Clients make requests to take (acquire) or return (release) one resource
- A request should only succeed if there is a resource available,
- Otherwise the request must block
Implementation using monitors
One condition variable (to wait till more resources are available)
private final Condition moreResources = lock.newCondition();
Internal data structures
int units = 0 ; // Counts the number of elements private Queue
store ; // Queue to store the elements Allocation
public E allocate() throws InterruptedException { E r ; lock.lock() ; while (units == 0) moreResources.await() ; units-- ; r = store.remove() ; lock.unlock() ; return r ; }
Release
public void release(E elem) { lock.lock() ; store.add(elem) ; moreResources.signal() ; lock.unlock() ; }
Does it work?
What about asking for several resources at the same time?
Resource allocation problem (multiple requests)
Clients requiring multiple resources should not ask for resources one at a time
- Why would this be bad?
Clients make requests to take or return any number of the resources
A request should only succeed if there are sufficiently many resources available,
Otherwise the request must block
Allocation
public Set
allocate(int n) throws InterruptedException { Set r = new TreeSet () ; lock.lock() ; while (units < n) moreResources.await() ; units-=n ; for (int i = 0 ; i < n ; i++) r.add(store.remove()) ; lock.unlock() ; return r ; } Release
public void release(TreeSet
elems) { lock.lock() ; store.addAll(elems) ; units = units + elems.size() ; moreResources.signal() ; lock.unlock() ; }
Nested monitor calls
- What happens if monitor A calls monitor B?
Four approaches
Ban nested calls
Release A's lock when entering B's lock
- Promotes concurrency
Maintain lock on A while in B
await
on B releases both locks
Maintain lock on A while in B
await
on B only releases B's lockLess concurrency
It can lead to deadlock
What about Java?
It maintains the A's lock while entering B
A
await
operation only releases the lock associated to the condition variableA thread might block while holding locks!
- Good chance for deadlock!
Summary
Reader/Writer problem
Fairness issues
We solved some of them
Resource/allocator
Requests for a single element
Requests for multiple instances
- Deadlock possibilities and how to avoid it
Nested monitors calls