Professional Documents
Culture Documents
Monitor Examples
Monitor Examples
Problems
Announcements
CS 415 Projects graded.
Mean 80.7, High 90 out of 90
Review: Monitors
Monitors represent the logic of the program
Wait if necessary
Signal when change something so any waiting threads can
proceed
Problem Definition
Correctness Constraints:
Consumer must wait for producer to fill buffers, if none full
scheduling constraint
Producer
Consumer
char get() {
P(not_full);
P(mutex);
P(not_empty);
P(mutex);
// add ch to buffer
buf[head%N] = ch;
head++;
V(mutex);
V(not_empty);
V(mutex);
V(not_full);
}
return ch;
Is order of Ps important?
Yes! Can cause deadlock
Is order of Vs important?
No, except that it might affect scheduling efficiency
Cleaner idea: Use locks for mutual exclusion and condition variables
for scheduling constraints
Condition Variables
How do we change the get() routine to wait until something is
in buffer?
Could do this by keeping a count of the number of things on the
queue (with semaphores), but error prone
Operations:
Wait(&lock): Atomically release lock and go to sleep. Re-acquire
lock later, before returning.
Signal(): Wake up one waiter, if any
Broadcast(): Wake up all waiters
char get() {
while(n == 0)
wait(not_empty);
ch = buf[tail%N];
tail++;
n--;
signal(not_full);
return ch;
}
10
11
12
14
15
R
R
16
Writer()
17
18
Void BeginRead()
{
if(NWriters == 1 || WaitingWriters > 0)
{
++WaitingReaders;
Wait(CanRead);
--WaitingReaders;
}
++NReaders;
Signal(CanRead);
}
Void EndRead()
{
if(--NReaders == 0)
Signal(CanWrite);
}
19
Void BeginRead()
{
if(NWriters == 1 || WaitingWriters > 0)
{
++WaitingReaders;
Wait(CanRead);
--WaitingReaders;
}
++NReaders;
Signal(CanRead);
}
Void EndRead()
{
if(--NReaders == 0)
Signal(CanWrite);
}
20
Void BeginRead()
{
if(NWriters == 1 || WaitingWriters > 0)
{
++WaitingReaders;
Wait(CanRead);
--WaitingReaders;
}
++NReaders;
Signal(CanRead);
}
Void EndRead()
{
if(--NReaders == 0)
Signal(CanWrite);
}
21
Void BeginRead()
{
if(NWriters == 1 || WaitingWriters > 0)
{
++WaitingReaders;
Wait(CanRead);
--WaitingReaders;
}
++NReaders;
Signal(CanRead);
}
Void EndRead()
{
if(--NReaders == 0)
Signal(CanWrite);
}
22
23
Void BeginRead()
{
if(NWriters == 1 || WaitingWriters > 0)
{
++WaitingReaders;
Wait(CanRead);
--WaitingReaders;
}
++NReaders;
Signal(CanRead);
}
Void EndRead()
{
if(--NReaders == 0)
Signal(CanWrite);
}
24
25
Void BeginRead()
{
if(NWriters == 1 || WaitingWriters > 0)
{
++WaitingReaders;
Wait(CanRead);
--WaitingReaders;
}
++NReaders;
Signal(CanRead);
}
Void EndRead()
{
if(--NReaders == 0)
Signal(CanWrite);
}
26
27
Void BeginRead()
{
if(NWriters == 1 || WaitingWriters > 0)
{
++WaitingReaders;
Wait(CanRead);
--WaitingReaders;
}
++NReaders;
Signal(CanRead);
}
Void EndRead()
{
if(--NReaders == 0)
Signal(CanWrite);
}
28
29
Subtle aspects?
The code is simplified because we know there can only
be one writer at a time
It also takes advantage of the fact that signal is a no-op if
nobody is waiting
Where do we see these ideas used?
In the EndWrite code (it signals CanWrite without checking for
waiting writers)
In the EndRead code (same thing)
In StartRead (signals CanRead at the end)
30
31