Monitors, Condition Variables, and Readers-Writers

Slides:



Advertisements
Similar presentations
Operating Systems Semaphores II
Advertisements

Synchronization NOTE to instructors: it is helpful to walk through an example such as readers/writers locks for illustrating the use of condition variables.
Ch 7 B.
Chapter 6: Process Synchronization
Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition, Chapter 6: Process Synchronization.
CH7 discussion-review Mahmoud Alhabbash. Q1 What is a Race Condition? How could we prevent that? – Race condition is the situation where several processes.
1 Semaphores and Monitors CIS450 Winter 2003 Professor Jinhua Guo.
1 Semaphores and Monitors: High-level Synchronization Constructs.
COSC 3407: Operating Systems Lecture 8: Semaphores, Monitors and Condition Variables.
CS162 Operating Systems and Systems Programming Lecture 8 Readers-Writers Language Support for Synchronization February 13, 2006 Prof. Anthony D. Joseph.
CS162 Operating Systems and Systems Programming Lecture 8 Readers-Writers Language Support for Synchronization September 26, 2005 Prof. John Kubiatowicz.
Monitors CSCI 444/544 Operating Systems Fall 2008.
CS162 Operating Systems and Systems Programming Lecture 8 Readers-Writers Language Support for Synchronization September 25, 2006 Prof. John Kubiatowicz.
Race Conditions CS550 Operating Systems. Review So far, we have discussed Processes and Threads and talked about multithreading and MPI processes by example.
U NIVERSITY OF M ASSACHUSETTS, A MHERST Department of Computer Science Emery Berger University of Massachusetts, Amherst Operating Systems CMPSCI 377 Lecture.
Instructor: Umar KalimNUST Institute of Information Technology Operating Systems Process Synchronization.
Monitor Solutions to Classical Problems. 2 Announcements CS 415 Projects graded. –Mean 80.7, High 90 out of 90 CS 414 Homework due Monday.
Monitors: An Operating System Structuring Concept
Pthread (continue) General pthread program structure –Encapsulate parallel parts (can be almost the whole program) in functions. –Use function arguments.
Semaphores and Bounded Buffer Andy Wang Operating Systems COP 4610 / CGS 5765.
U NIVERSITY OF M ASSACHUSETTS, A MHERST Department of Computer Science Emery Berger University of Massachusetts, Amherst Operating Systems CMPSCI 377 Lecture.
6.3 Peterson’s Solution The two processes share two variables: Int turn; Boolean flag[2] The variable turn indicates whose turn it is to enter the critical.
Semaphores and Bounded Buffer. Semaphores  Semaphore is a type of generalized lock –Defined by Dijkstra in the last 60s –Main synchronization primitives.
Processes and Threads-V Concurrency and Synchronization.
COMP 111 Threads and concurrency Sept 28, Tufts University Computer Science2 Who is this guy? I am not Prof. Couch Obvious? Sam Guyer New assistant.
CS162 Operating Systems and Systems Programming Lecture 5 Semaphores, Conditional Variables February 2, 2011 Ion Stoica
11/21/20151 Operating Systems Design (CS 423) Elsa L Gunter 2112 SC, UIUC Based on slides by Roy Campbell, Sam.
CS162 Operating Systems and Systems Programming Lecture 7 Readers-Writers Language Support for Synchronization February 13, 2008 Prof. Anthony D. Joseph.
Today’s Agenda  Quick Review  Semaphore and Lock Advanced Topics in Software Engineering 1.
1 Synchronization Threads communicate to ensure consistency If not: race condition (non-deterministic result) Accomplished by synchronization operations.
1 Condition Variables CS 241 Prof. Brighten Godfrey March 16, 2012 University of Illinois.
Problems with Semaphores Used for 2 independent purposes –Mutual exclusion –Condition synchronization Hard to get right –Small mistake easily leads to.
CS533 – Spring Jeanie M. Schwenk Experiences and Processes and Monitors with Mesa What is Mesa? “Mesa is a strongly typed, block structured programming.
COSC 3407: Operating Systems Lecture 9: Readers-Writers and Language Support for Synchronization.
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Computer Systems Principles Synchronization Emery Berger and Mark Corner University.
CS162 Operating Systems and Systems Programming Lecture 8 Readers-Writers Language Support for Synchronization Friday 11, 2010 Ion Stoica
1 Previous Lecture Overview  semaphores provide the first high-level synchronization abstraction that is possible to implement efficiently in OS. This.
Dining Philosophers & Monitors Questions answered in this lecture: How to synchronize dining philosophers? What are monitors and condition variables? What.
Implementing Lock. From the Previous Lecture  The “too much milk” example shows that writing concurrent programs directly with load and store instructions.
3/17/2016cse synchronization-p2 © Perkins, DW Johnson and University of Washington1 Synchronization Part 2 CSE 410, Spring 2008 Computer.
Implementing Mutual Exclusion Andy Wang Operating Systems COP 4610 / CGS 5765.
© Janice Regan, CMPT 300, May CMPT 300 Introduction to Operating Systems Mutual Exclusion Mutexes, Semaphores.
CS162 Section 2. True/False A thread needs to own a semaphore, meaning the thread has called semaphore.P(), before it can call semaphore.V() False: Any.
CS703 - Advanced Operating Systems
2 July 2015 Charles Reiss
CS703 – Advanced Operating Systems
Background on the need for Synchronization
CS162 Operating Systems and Systems Programming Lecture 6 Readers/Writers Problem, Working in Teams February 10, 2014 Anthony D. Joseph
Semaphores and Condition Variables
Sarah Diesburg Operating Systems COP 4610
Andy Wang Operating Systems COP 4610 / CGS 5765
September 17, 2012 Ion Stoica CS162 Operating Systems and Systems Programming Lecture 6 Readers/Writers Problem,
Anthony D. Joseph and Ion Stoica
Process Synchronization
CS703 - Advanced Operating Systems
Anthony D. Joseph and John Canny
Implementing Mutual Exclusion
CSE 451: Operating Systems Autumn Lecture 8 Semaphores and Monitors
February 6, 2013 Ion Stoica CS162 Operating Systems and Systems Programming Lecture 5 Semaphores, Conditional Variables.
Implementing Mutual Exclusion
CSE 451: Operating Systems Autumn Lecture 7 Semaphores and Monitors
Kernel Synchronization II
September 12, 2012 Ion Stoica CS162 Operating Systems and Systems Programming Lecture 5 Semaphores, Conditional Variables.
Chapter 6: Synchronization Tools
Homework 4.
CS333 Intro to Operating Systems
EECE.4810/EECE.5730 Operating Systems
Don Porter Portions courtesy Emmett Witchel
September 19, 2018 Prof. Ion Stoica
Review The Critical Section problem Peterson’s Algorithm
Presentation transcript:

Monitors, Condition Variables, and Readers-Writers Mark Stanovich Operating Systems COP 4610

Motivation for Monitors Semaphores are a big step from the low-level loads and stores However, semaphores are used for both mutual exclusion and scheduling The idea of monitors is to separate these two concerns

Monitor Defined Monitor: a lock + condition variables Lock: provides mutual exclusion to shared data Condition variable: provides a queue for waiting threads inside a critical section

Locks A lock provides two operations: Lock::Acquire() Lock::Release() Wait until the lock is free, then grab it Lock::Release() Unlock, wake up anyone waiting to Acquire A lock is initially free

More on Locks Always acquire a lock before accessing a shared data structure Always release the lock after finishing with the shared data structure

An Example of Using Locks AddToBuffer() { Lock.Acquire(); // put 1 item to the buffer Lock.Release(); } RemoveFromBuffer() { // if something in the buffer // remove 1 item form the buffer return item;

Condition Variables We need additional mechanisms to wait inside locked regions However, holding the lock while waiting prevents other threads from entering the locked region Condition variables make it possible to sleep inside a critical section Atomically release the lock & go to sleep

Condition Variables Each condition variable Consists of a queue of threads Provides three operations Wait(); Atomically release the lock and go to sleep Reacquire lock on return Signal(); Wake up one waiting thread, if any Broadcast(); Wake up all waiting threads

Condition Variables Note The three operations can only be used inside locked regions

An Example of Using Condition Variables AddToBuffer() { lock.Acquire(); // put 1 item to the buffer condition.Broadcast(&lock); // move threads from the // wait queue to the ready queue // do something else lock.Release(); } RemoveFromBuffer() { while nothing in the buffer { condition.Wait(&lock); // implicit lock release // implicit lock acquire return item;

Hoare vs. Mesa Monitors Hoare Monitors (used in most textbooks) Signal() transfers the CPU directly to a waiting thread

Mesa vs. Hoare Monitors Mesa Monitors (used in most real operating systems) Signal() only puts a waiting thread on the scheduler’s ready queue By the time the waken thread gets the CPU, the waiting condition may no longer be true and needs to be retested

Readers-Writers Problem Commonly seen in database applications Readers never modify the database Writers read and modify the database We want one writer at a time, but many readers at the same time

Constraints A reader should wait when a writer is accessing or waiting for the database Condition okToRead A write should wait when there is a reader or writer accessing the database Condition okToWrite A reader or a writer should wait when someone is modifying global states Lock lock

Basic Structure of the Solution Reader Wait until no writers Access database Wake up waiting writers Writer Wait until no active readers or writers Wake up waiting readers or writers

Developing the Solution Global states: activeReaders = 0; activeWriters = 0; waitingReaders = 0; waitingWriters = 0; Condition okToRead = NULL; Condition okToWrite = NULL; Lock lock = FREE;

Put in Locks and Some Global States Reader() { lock.Acquire(); ++activeReaders; lock.Release(); // access database --activeReaders; } Writer() { lock.Acquire(); ++activeWriters; lock.Release(); // access database --activeWriters; }

Add the Wait Condition for Reader lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; Writer() { lock.Acquire(); ++activeWriters; lock.Release(); // access database --activeWriters; }

Add the Wait Condition for Writer Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters;

Add the Signal Condition for Reader lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters;

Add the Signal Condition for Writer Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Code Demonstration Reader() { lock.Acquire(); while (activeWriters > 0 || waitingWriters > 0) { ++waitingReaders; okToRead.Wait(&lock); --waitingReaders; } ++activeReaders; lock.Release(); // access database --activeReaders; if (activeReaders == 0 && waitingWriters > 0) { okToWrite.Signal(&lock); Writer() { lock.Acquire(); while (activeWriters > 0 || activeReaders > 0) { ++waitingWriters; okToWrite.Wait(&lock); --waitingWriters; } ++activeWriters; lock.Release(); // access database --activeWriters; if (waitingWriters > 0) { okToWrite.Signal(&lock); } else if (waitingReaders > 0) { okToRead.Broadcast(&lock);

Semaphores vs. Monitors Can we implement monitors with semaphores? Wait() { P(s); } Signal() { V(s);

Semaphores vs. Monitors Not quite… Condition variables only work inside a lock Using semaphores inside a lock may deadlock

Semaphores vs. Monitors Condition variables have no history, but semaphores have Signal() with an empty queue does nothing A subsequent Wait() will wait V() increments semaphore A subsequent P() will not wait