Using Mesa-Style Monitors
Using Mesa-Style Monitors
n Monitors combine:
n Locking for mutual exclusion
Condition variables to represent scheduling constraints
Threads: Wrap Up
n
lock.Acquire(); lock.Acquire();
lock.Release(); lock.Release();
lock.Acquire(); lock.Acquire(); n Using a single lock on the database would be overly restrictive
n want many readers at the same time
1
Solving Readers/writers Solving readers/writers
n Reader: Reader() { Writer() {
n When ok to proceed? AW = 0 lock.Acquire(); lock.Acquire();
while (AW > 0) { while ((AW+AR) > 0) {
n What to wait on? okToRead condition variable WR ++; WW ++;
n How to update state variables? AR++ or WR++ or AR– or WR— okToRead.Wait(&lock);
okToWrite.Wait(&lock);
When to signal? If AR == 0 && WW > 0, signal okToWrite WR --;
n WW --;
}
AR++; }
AW++;
n Writer: lock.Release();
lock.Release();
n When ok to proceed? AR = 0 & AW = 0 Access DB;
Access DB;
n What to wait on? okToWrite condition variable lock.Acquire();
AR--; lock.Acquire();
n How to update state variables? AW++ or WW++ or AW– or WW—
if (AR == 0 && WW > 0) AW--;
n When to signal? okToWrite.Signal(&lock); if (WW > 0) okToWrite.Signal(&lock);
n If waiting writers, signal okToWrite lock.Release(); else if (WR > 0) okToRead.Broadcast(&lock);
}
n If waiting readers, broadcast okToRead lock.Release();
}
n Solution is not relinquishing the lock: n Too much history! Semaphore updates are remembered for ever
n Consider behavior of condition variables:
lock.Acquire();
lock.Acquire(); n What if thread signals and no one is waiting? No op.
n What if another thread later performs a “wait”? It blocks.
if (!condition)
Wait(); Signal(); n Compare with behavior of semaphores:
n What if thread V’s and no one is waiting? Increment
lock.Release(); n What if another thread later performs a P? Decrement and continue
lock.Release();
2
Third Attempt Implementing Monitors
n Does this fix the problem? Using one semaphore for each waiting thread --- making sure it indeed gets
the message when it is signalled.
Signal()
{
class Condition { List waitQueue; }
if semaphore queue is not empty
semaphore->V(); Condition::Wait(Lock* lock) { Condition::Signal(Lock* lock) {
} Semaphore *w; Semaphore *w;
n Well, it is cheating…
w = new Semaphore (0); if anyone on waitQueue {
n But also wrong: add w to the waitQueue; Take a waiting element off
n Race condition: signaller can slip in after lock is released and before lock->Release(); and name it w;
wait. w->P(); w->V();
lock->Acquire(); }
n Signal is lost. What did we violate: the atomic release + wakeup
delete w; }
property
}
n Every major OS built since 1985 has provided threads n Might have 90 threads, but just a few on the ready queue
n Mach, OS/2, NT, Solaris, OSF
n Makes it a lot easier to write concurrent programs: web servers, n Result: system needs an extra 1MB of memory, consumed by waiting
threads. 1MB cost $200 in 1988
databases, embedded systems
n Did OS/2 run Excel or Word better? Ok, it gave you the ability to keep
n Does this mean that we should all go out and use threads? working when you use the printer, but is that worth $200?
Performance Issues
n Consider parallel programs: for example, matrix multiplication: