Monitors: An

Operating System
Structuring
Concept
Paper by C. A. R. Hoare
Presentation by
Emerson Murphy-Hill

The Problem
• An OS’s main task is to control
access to a machine’s resources
(data, devices, time, space)
• If resources are not tightly
controlled, “chaos will ensue”
- race conditions

The Solution • Monitors provide control by allowing only one process to access a critical resource at a time – A class/module/package – Contains procedures and data .

An Abstract Monitor name : monitor … some local declarations … initialize local data procedure name(…arguments) … do some work … other procedures .

Monitor Rules • Any process can access any monitor procedure at any time • Only one process may enter a monitor procedure • No process may directly access a monitor’s local variables • A monitor may only access it’s local variables .

Things Needed to Enforce Monitor • “wait” operation – Forces running process to sleep • “signal” operation – Wakes up a sleeping process • A condition – Something to store who’s waiting for a particular reason – Implemented as a queue .

signal. nonOccupied. occupied = true. Procedure . Declarations / Initialization procedure enterKitchen if occupied then nonOccupied.A Running Example – Emerson’s Kitchen kitchen : monitor Monitor Declaration occupied : Boolean. nonOccupied : condition. Procedure procedure exitKitchen occupied = false.wait. occupied := false.

Multiple Conditions • Sometimes desirable to be able to wait on multiple things • Can be implemented with multiple conditions • Example: Two reasons to enter kitchen .cook (remove clean dishes) or clean (add clean dishes) • Two reasons to wait: – Going to cook. but no clean dishes – Going to clean. no dirty dishes .

wait dishes.push (sink. dishes.wait sink.pop ).Emerson’s Kitchen kitchen : monitor cleanDishes.isEmpty then dirtyDishes.signal.pop) cleanDishes.signal . dirtyDishes.push ( dishes. sink : stack. procedure cleanDish if sink. dishes := stack of 10 dishes sink := stack of 0 dishes procedure cook if dishes.isEmpty then cleanDishes. dirtyDishes : condition.

Condition Queue • Checking if any process is waiting on a condition: – “condition.queue” returns true if a process is waiting on condition • Example: Doing dishes only if someone is waiting for them .

pop). dirtyDishes : condition.signal.isEmpty then cleanDishes.push ( dishes.wait if cleanDishes.Emerson’s Kitchen kitchen : monitor cleanDishes.isEmpty then dirtyDishes. .signal.queue dishes. dishes := stack of 10 dishes sink := stack of 0 dishes procedure cook if dishes. procedure cleanDishes if sink.pop ).wait sink. sink : stack.push (sink. dirtyDishes. dishes. cleanDishes.

Scheduled Waits • Gives a waiting thread a number • Lowest number gets woken up first (inverse priority) • Example: People who want to cook are prioritized: – Highest: Me! – Medium: Family – Lowest: Vagrants/Friends .

wait(1). while(cleanDishes.isFamily then cleanDishes. dishes. dirtyDishes. if p.queue) dishes. dirtyDishes : condition.isFriendAndOrVagrant then cleanDishes.pop ).push (sink.isEmpty then if p.push ( dishes.signal.signal.isEmerson then cleanDishes.wait(3).isEmpty then dirtyDishes. sink. cleanDishes. dishes := stack of 10 dishes sink := stack of 0 dishes procedure cook( p : Person ) if dishes. sink : stack.Emerson’s Kitchen kitchen : monitor cleanDishes. procedure cleanDishes if sink.wait. .wait(2).pop). if p.

semaphores or locks) – Better encapsulation • Disadvantages: – Deadlock still possible (in monitor code) – Programmer can still botch use of monitors – No provision for information exchange between machines .Summary • Advantages – Data access synchronization simplified (vs.

Other Issues Discussed • Power of Monitors – SemaphoreMonitor – MonitorSemaphore • Proof Rules – I (b.signal) I • OS Examples – Bounded Buffer – Alarm clock – Buffer allocation – Disk-head Scheduler – Reader/Writer .wait) I & B – I & B (b.

acquire(). occupied = true. occupied : Boolean. enableInterrupts(). occupied := false. nonOccupied : condition. procedure enterKitchen procedure enterKitchen disableInterrupts(). if occupied then nonOccupied. enableInterrupts(). nonOccupied. lock1. occupied := false.signal. lock1. . lock1.signal. procedure exitKitchen procedure exitKitchen disableInterrupts(). nonOccupied : condition. if occupied then nonOccupied. occupied = false.wait.Mutual Exclusion: Implementation Disabling Interrupts Mutex Insertion kitchen : monitor kitchen : monitor occupied : Boolean.wait.release().acquire(). lock1 : lock. occupied = true. lock1. nonOccupied. occupied = false.release().

but of course.Monitors In Context • Multithreaded code could be implemented with monitors (w/language support) • Enforcement of mutex locking conventions • Abstraction: deadlock can be avoided. only if the monitor is written correctly! .

Conclusion • Monitors are a synchronization mechanism • A higher level. better encapsulation vs. semaphores/locks • Monitors still suffer from various afflictions . easier to use abstraction.

Tannenbaum. pp. 115-119.” Hoare. • Jon Walpole. . Second Edition. • Modern Operating Systems.References • “Monitors: An Operating System Structuring Concept. correspondence.

Generally. What is the essential implementation difference between monitors and semaphores? 2. What problems can still arise with the use of monitors? 3. What is the most specialized compiler mechanism required to implement monitors? 4.Questions 1. monitors allow us to encapsulate mutex use and avoid the spread of mutex across code. Can you think of a case where this is not possible? .

When we need uninterrupted access to 2 or more resources located in different monitor proceedures. acquire without release) 3. . Mutual exclusion in monitor methods 4. inconsistent use (eg. Atomicity of blocked code-reentrance in monitors 2. Deadlock.Possible Answers 1.