synchronicity ii introduction to operating systems: module 6
DESCRIPTION
Review u Solutions to the critical section problem (CSP) Software Petersen’s algorithm (2 processes) Bakery algorithm (3 or more processes) Hardware Disable interrupts Special instructions (can’t solve the problem alone) OS primitives (introduced in this module) Semaphores MonitorsTRANSCRIPT
Synchronicity II
Introduction to Operating Systems: Module 6
Review Synchronization
The problem of getting processes to work together Poor synchronization can result in a race condition
Two people access the same bank account via ATM The naïve solution to the bounded buffer problem
The critical section problem Is an instance of synchronization Formal criteria for a solution
Traditional: mutual exclusion, progress, bounded wait Last time: 6 equivalent, less difficult criteria
Review Solutions to the critical section problem (CSP)
Software Petersen’s algorithm (2 processes) Bakery algorithm (3 or more processes)
Hardware Disable interrupts Special instructions (can’t solve the problem alone)
OS primitives (introduced in this module) Semaphores Monitors
Software solutions to CSP Some solutions are hard to program, debug
Bakery algorithm Waiting processes are busy
Wastes CPU cycles It would be better to block the process
Like waiting for I/O Incurs overhead of a context switch Not efficient for very short critical sections
Hardware solutions to CSP: disable interrupts
On a uniprocessor: mutual exclusion is preserved but efficiency of execution is degraded: while in CS, we cannot interleave execution with other processes that are in RS
On a multiprocessor: mutual exclusion is not achieved
Generally not an acceptable solution
repeat disable interrupts critical section enable interrupts remainder sectionforever
Hardware solutions to CSP: Special machine instructions
Machine instructions can perform 2 actions atomically (indivisible) on the same memory location (ex: reading and testing)
The execution of such an instruction is mutually exclusive (even with multiple CPUs)
They can be used simply to provide mutual exclusion but need more complex algorithms for satisfying the requirements of the CSP
Synchronization Primitives
SemaphoresMonitors
Semaphores A semaphore is an abstract data
type Semaphores can be implemented
through Busy wait Blocking via system calls
Semaphores have a 2 method interface Wait( ) Signal( )
Wait Signal
Semaphore
Busy waiting semaphores
The simplest way to implement semaphores
Useful when critical sections last for a short time, or we have lots of CPUs
I is initialized to positive value (to allow someone in at the beginning)
S.wait(){ while (I<=1); I--;} S.signal(){ I++;}
I
Semaphore
Integer
Atomicity aspects
The testing and decrementing sequence in wait are atomic, but not the loop
Signal is atomic No two processes can be
allowed to execute atomic sections simultaneously
This can be implemented by other mechanisms, such as test-and-set
S.wait:
I <= 1
I - -
atomic
F
T
Using semaphores for solving critical section problems
For n processes Initialize I to 1 Then only 1 process is
allowed into CS (mutual exclusion)
To allow k processes into CS, we initialize I to k
Process Pi:repeat S.wait(); CS S.signal(); RSforever
Signal to a waiting process
Process Pi:repeat S.wait(); CS S.signal(); RSforever
Process Pj:repeat S.wait(); CS S.signal(); RSforever
Semaphores: the global view
Initialize I to 1
Semaphores synchronize processes
We have 2 processes: P1 and P2
Statement S1 in P1 needs to be performed before statement S2 in P2
Then define a semaphore “synch”
Initialize synch to 0
Proper synchronization is achieved by having in P1: S1; synch.signal();
And having in P2: synch.wait(); S2;
Semaphores: observations
When initial I>=0: the number of processes that can execute S.wait()
without being blocked = I I processes can enter the “limited capacity” section
When I becomes >=0, which waiting process enters the critical section? FCFS? Not specified Implementation dependent
Avoiding busy wait in semaphores To avoid busy waiting: when a process has to wait for a
semaphore to become greater than 0, it will be put in a blocked queue of processes waiting for this to happen
Queues can be FIFO, priority, etc.: OS has control on the order processes enter CS
In practice, wait and signal become system calls to the OS (such as I/O), which contains the semaphore implementation
There is a queue for every semaphore just as there is a queue for each I/O unit
Semaphores without busy waiting
class semaphore { private: int I; ProcessQueue queue; public: void signal(); void wait();} When a process must wait for a
semaphore S, it is blocked and put on the semaphore’s queue
The signal operation removes (by a fair policy like FIFO) one process from the queue and puts it in the list of ready processes
S.wait() { S.I--; if (S.I<0) S. enqueue(p)} S.signal(){ I++; if (s.I<=0) S.dequeue();}
Semaphore
Queue
-3 I
Semaphore’s operations (atomic)
S.wait() { S.I--; if (S.I<0) { block this process
place this process in S.queue}}
S.signal(){S.I++; if (S.I<=0) { remove a process from S.queue place it on ready list }}
The value to which S.count is initialized depends on the application
Semaphores: implementation wait and signal themselves contain critical
sections! How to implement them? Note that they are very short critical sections Solutions:
uniprocessor: disable interrupts during these operations (i.e.: for a very short period)
This does not work on a multiprocessor machine multiprocessor: use some busy waiting scheme
Busy waiting shouldn’t last long
Binary semaphores Similar to counting semaphores except that “count”
is Boolean valued Perhaps simpler to implement Can do anything counting semaphores can do Requires writing more code than counting
semaphores: must use additional counting variables protected by binary semaphores
Binary semaphoreswaitB(S){ if (S.value = 1) S.value = 0; else { block(this) S.queue.add(this) }}
signalB(S){ if (S.queue is empty) S.value = 1; else { process = S.queue.next(); readyQueue.add(process); }}
Semaphores Semaphores provide a structured tool for enforcing
mutual exclusion and coordinate processes. Avoid bus wait, but not completely. If used correctly, avoid deadlock and starvation. But if wait(S) and signal(S) are scattered among
several processes it may be difficult to use them correctly
Usage must be correct in all processes One bad (or malicious) process can fail the entire
collection of processes, cause deadlock, starvation
Monitors
Are high-level language constructs that provide equivalent functionality to that of semaphores but are easier to control
Found in many concurrent programming languages
Concurrent Pascal, Modula-3, C++, Java… Very appropriate for OO programming However each language has own ‘dialect’
Monitor Is a software module containing:
one or more procedures an initialization sequence local data variables
Characteristics: local variables accessible only by monitor’s procedures a process enters the monitor by invoking one of its
procedures only one process can be in the monitor at any given time
Monitor
The monitor ensures mutual exclusion: no need to program this constraint explicitly
Shared data within the monitor are protected The monitor locks on process entry Only one process can execute in the monitor at a time
Process synchronization is done by the programmer by using condition variables represent conditions on which a process may wait for
before executing in the monitor
Condition variables are local to the monitor
(accessible only within the monitor) have ADT methods:
cwait(a): blocks execution of the calling process on condition variable a
process can resume execution only if another process executes csignal(a)
csignal(a): resume execution of some process blocked on condition variable a
If several such process exists: choose any one (fifo or priority) If no such process exists: do nothing
Monitor Awaiting processes are either in
the entrance queue or in a condition queue
A process puts itself into condition queue cn by issuing cwait(cn)
csignal(cn) brings into the monitor 1 process in condition cn queue
Hence csignal(cn) blocks the calling process and puts it in the urgent queue (unless csignal is the last operation of the monitor procedure)
Monitors for the bounded buffer
Monitor needs to hold the buffer: buffer: array[0..k-1] of items;
needs two condition variables: notfull: csignal(notFull) when buffer becomes not full notempty: csignal(notEmpty) when the becomes not empty
needs buffer pointers and counts: nextin: points to next slot to be filled nextout: points to next item to be taken count: holds the number of items in buffer
No race condition: monitor ensures mutual exclusion!
Monitor for the bounded P/C problemMonitor boundedbuffer{ items buffer[k]; int nextin=0, nextout=0, count=0; condition notfull, notempty; //buffer statevoid append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ % k; count++; csignal(notempty);}
item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ % k; count--; csignal(notfull); return v;}}
Monitor Monitors result in simpler, easier to read code, and
provide synchronization via condition variables They are not, however, able to do things
semaphores cannot: they can be implemented with semaphores, and vice versa
Monitor exampleMonitor boundedbuffer{buffer[ | | | ]nextin=0 nextout=0 count=0 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Running process
Monitor exampleMonitor boundedbuffer{buffer[ 1 | | | ];nextin=0 nextout=0 count=0 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | | | ]nextin=1 nextout=0 count=0 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | | | ]nextin=1 nextout=0 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | | | ]nextin=1 nextout=0 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | | | ]nextin=1 nextout=0 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=1 nextout=0 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=0 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=0 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=0 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=0 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=0 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=1 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=1 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=1 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | | ]nextin=2 nextout=1 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | ]nextin=2 nextout=1 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | ]nextin=3 nextout=1 count=1 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | ]nextin=3 nextout=1 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | ]nextin=3 nextout=1 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | ]nextin=3 nextout=1 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | 4 ]nextin=3 nextout=1 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | 4 ]nextin=0 nextout=1 count=2 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | 4 ]nextin=0 nextout=1 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | 4 ]nextin=0 nextout=1 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 1 | 2 | 3 | 4 ]nextin=0 nextout=1 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=0 nextout=1 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=1 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=1 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=1 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=1 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=1 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=2 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=2 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 2 | 3 | 4 ]nextin=1 nextout=2 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=1 nextout=2 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=2 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=3 count=4 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=3 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Monitor exampleMonitor boundedbuffer{buffer[ 5 | 6 | 3 | 4 ]nextin=2 nextout=3 count=3 k=4
void append(item v){ if (count==k) cwait(notfull); buffer[nextin]= v; nextin++ mod k; count++; csignal(notempty);}item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ mod k; count--; csignal(notfull); return v;}}
notfullnotempty
Who goes first?
Who goes first? When a condition variable with a nonempty queue
is signaled, which process executes in the monitor? The signaled process: Hoare semantics The signaling process: Mesa (Brinch-Hansen) semantics
If the signaled process does not immediately execute in the monitor, it is possible that the signaled condition could be come invalid Using Mesa semantics the signaled process must recheck
the condition, waiting on the associated condition variable if it is false
Hoare vs. Mesa semantics: usageMonitor boundedbuffer{ items buffer[k-1]; int nextin=0, nextout=0; int count=0; condition notfull, notempty; void append(item v){ if (count==k)
cwait(notfull); buffer[nextin]= v; nextin++ % k; count++; csignal(notempty);}
item take(){item v; if (count==0) cwait(notempty); v= buffer[nextout]; nextout++ % k; count--; csignal(notfull); return v;}}
Monitor boundedbuffer{ items buffer[k-1]; int nextin=0, nextout=0; int count=0; condition notfull, notempty; void append(item v){ while(count==k) cwait(notfull); buffer[nextin]= v; nextin++ % k; count++; csignal(notempty);}
item take(){item v; while(count==0) cwait(notempty); v= buffer[nextout]; nextout++ % k; count--; csignal(notfull); return v;}}
Message passing Processes (and threads) can communicate without
synchronization Shared memory
A message passing paradigm for communication requires synchronization Send (destination, message)
What if the source has not yet called receive? Receive(source, message)
What if no message was sent?
Blocking vs. non-blocking After calling send, if no matching receive
The sender could block until the message is received The sender could continue
After calling receive, if no matching send The caller could block until a message is sent
Test function (Are there pending messages?) Time out (Wait until message or X seconds have passed)
The caller could continue, with receive returning failure
Direct vs. Indirect If the source/destination arguments are process
identifiers, the system uses direct messaging If the source/destination arguments are mailboxes,
possibly shared by many processes, the system uses indirect messaging Many senders, one receiver (client server) Many receivers, many senders (topic subscription) Who owns the mailbox?
Message passing as synchronization Semaphores or monitors may be used to implement
message passing A message passing system can be used to
implement monitors or semaphores Message passing has the same synchronization
power as semaphores and monitors