CS162 Operating Systems and Systems Programming Lecture 6 Readers/Writers Problem, Working in Teams February 10, 2014 Anthony D. Joseph http://inst.eecs.berkeley.edu/~cs162.

Slides:



Advertisements
Similar presentations
Operating Systems Semaphores II
Advertisements

Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition, Chapter 6: Process Synchronization.
1 Semaphores and Monitors: High-level Synchronization Constructs.
COSC 3407: Operating Systems Lecture 8: Semaphores, Monitors and Condition Variables.
CS 162 Week 3 Discussion (2/13 – 2/14). Today’s Section Project Administrivia (5 min) Quiz (5 min) Review Lectures 6 and 7 (15 min) Worksheet and Discussion.
CS194-3/CS16x Introduction to Systems Lecture 3 Programming Techniques and Teams September 4, 2007 Prof. Anthony D. Joseph
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.
CS194-3/CS16x Introduction to Systems Lecture 7 Monitors, Readers/Writers problem, Language support for concurrency control, Relational model September.
CS162 Operating Systems and Systems Programming Lecture 8 Readers-Writers Language Support for Synchronization September 23, 2009 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.
U NIVERSITY OF M ASSACHUSETTS, A MHERST Department of Computer Science Emery Berger University of Massachusetts, Amherst Operating Systems CMPSCI 377 Lecture.
COMP 208/214/215/216 Lecture 3 Planning. Planning is the key to a successful project It is doubly important when multiple people are involved Plans are.
Testing. 2 Overview Testing and debugging are important activities in software development. Techniques and tools are introduced. Material borrowed here.
Kernel Locking Techniques by Robert Love presented by Scott Price.
Announcement Exercise Set 1 is released.  More problems will be added in next two weeks.  We will post a midterm sample this weekend or so (some problems.
CS162 Operating Systems and Systems Programming Lecture 5 Semaphores, Conditional Variables February 2, 2011 Ion Stoica
Chapter 7 The Practices: dX. 2 Outline Iterative Development Iterative Development Planning Planning Organizing the Iterations into Management Phases.
CS162 Operating Systems and Systems Programming Lecture 7 Readers-Writers Language Support for Synchronization February 13, 2008 Prof. Anthony D. Joseph.
CS 162 Discussion Section Week 4. Administrivia Design reviews Friday, Monday and Tuesday – Every member must attend – Will test that every member understands.
CSCI-375 Operating Systems Lecture Note: Many slides and/or pictures in the following are adapted from: slides ©2005 Silberschatz, Galvin, and Gagne Some.
1 Condition Variables CS 241 Prof. Brighten Godfrey March 16, 2012 University of Illinois.
13/03/07Week 21 CENG334 Introduction to Operating Systems Erol Sahin Dept of Computer Eng. Middle East Technical University Ankara, TURKEY URL:
Problems with Semaphores Used for 2 independent purposes –Mutual exclusion –Condition synchronization Hard to get right –Small mistake easily leads to.
CS162 Operating Systems and Systems Programming Lecture 6 Programming Techniques and Teams February 6, 2012 Anthony D. Joseph and Ion Stoica
COSC 3407: Operating Systems Lecture 9: Readers-Writers and Language Support for Synchronization.
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.
Implementing Lock. From the Previous Lecture  The “too much milk” example shows that writing concurrent programs directly with load and store instructions.
Implementing Mutual Exclusion Andy Wang Operating Systems COP 4610 / CGS 5765.
Mutual Exclusion -- Addendum. Mutual Exclusion in Critical Sections.
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.
Lecture 5 Page 1 CS 111 Summer 2013 Bounded Buffers A higher level abstraction than shared domains or simple messages But not quite as high level as RPC.
CS162 Operating Systems and Systems Programming Lecture 9 Synchronization, Readers/Writers example, Scheduling September 26th, 2016 Prof. Anthony D.
CS703 - Advanced Operating Systems
2 July 2015 Charles Reiss
CPS110: Reader-writer locks
CS703 – Advanced Operating Systems
1 July 2015 Charles Reiss CS162: Operating Systems and Systems Programming Lecture 7: Synchronization: Lock Implementation,
Atomic Operations in Hardware
Multiple Writers and Races
Monitors, Condition Variables, and Readers-Writers
Processes and Monitors in Mesa (Lecture 6, cs262a)
Taking an Iteration Down to Code
CSCI 511 Operating Systems Chapter 5 (Part C) Monitor
February 7, 2011 Ion Stoica CS162 Operating Systems and Systems Programming Lecture 6 Semaphores, Conditional Variables,
CS162 Operating Systems and Systems Programming Midterm Review
September 17, 2012 Ion Stoica CS162 Operating Systems and Systems Programming Lecture 6 Readers/Writers Problem,
COMP 208/214/215/216 Lecture 3 Planning.
Anthony D. Joseph and Ion Stoica
CS162 Operating Systems and Systems Programming Midterm Review
CS703 - Advanced Operating Systems
Anthony D. Joseph and John Canny
CSE 303 Concepts and Tools for Software Development
Anthony D. Joseph and Ion Stoica
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.
Monitor Giving credit where it is due:
Implementing Mutual Exclusion
September 12, 2012 Ion Stoica CS162 Operating Systems and Systems Programming Lecture 5 Semaphores, Conditional Variables.
CMSC 345 Programming.
CSE 153 Design of Operating Systems Winter 19
CS333 Intro to Operating Systems
EECE.4810/EECE.5730 Operating Systems
Software Engineering and Architecture
Don Porter Portions courtesy Emmett Witchel
September 19, 2018 Prof. Ion Stoica
Review The Critical Section problem Peterson’s Algorithm
Presentation transcript:

CS162 Operating Systems and Systems Programming Lecture 6 Readers/Writers Problem, Working in Teams February 10, 2014 Anthony D. Joseph http://inst.eecs.berkeley.edu/~cs162

Goals for Today Recap: Readers/Writers problem Locks, again Mesa monitors: Why use “while()”? Readers/Writers problem Tips for Programming in a Project Team Note: Some slides and/or pictures in the following are adapted from slides ©2005 Silberschatz, Galvin, and Gagne. Slides courtesy of Anthony D. Joseph, John Kubiatowicz, AJ Shankar, George Necula, Alex Aiken, Eric Brewer, Ras Bodik, Ion Stoica, Doug Tygar, and David Wagner.

More Recap: Locks A thread needs to wait if another one in critical section A critical section can be arbitrary long Don’t want to spin-lock while waiting; want to sleep! lock.Acquire(); … critical section; lock.Release();

More Recap: Locks A thread needs to wait if another one in critical section A critical section can be arbitrary long Don’t want to spin-lock while waiting; want to sleep! int value = FREE; Acquire() { if (value == BUSY) { put thread on wait-queue; go to sleep(); } else { value = BUSY; } } lock.Acquire(); … critical section; lock.Release(); Both bodies of Acquire() and Release() should be critical section. Why? Release() { if anyone on wait queue { take thread off wait queue place on ready queue; } else { value = FREE; }

More Recap: Locks Acquire() and Release() themselves need to be critical sections int guard = 0; int value = FREE; Acquire() { while(test&set(guard)); if (value == BUSY) { put thread on wait-queue; go to sleep()& guard = 0; } else { value = BUSY; guard = 0; } } spin-lock (but critical section very small!) lock.Acquire(); … critical section; lock.Release(); Release() { while (test&set(guard)); if anyone on wait queue { take thread off wait-queue; Place on ready queue; } else { value = FREE; } guard = 0; }

Mesa Monitor: Why “while()”? Why do we use “while()” instead of “if() with Mesa monitors? Example illustrating what happens if we use “if()”, e.g., if (queue.isEmpty()) { dataready.wait(&lock); // If nothing, sleep } We’ll use the synchronized (infinite) queue example AddToQueue(item) { lock.Acquire(); queue.enqueue(item); dataready.signal(); lock.Release(); } RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } Hoare Mesa: Replace “while” with “if”

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T1 Ready queue  NULL … queue lock: FREE dataready queue NULL T1 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T1 Ready queue  NULL … queue lock: BUSY (T1) dataready queue NULL T1 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: Ready queue  NULL … queue lock: FREE dataready queue T1 wait(&lock) puts thread on dataready queue and releases lock T1 (Waiting) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T2 Ready queue  NULL … queue lock: FREE dataready queue T1 T1 (Waiting) T2 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } AddToQueue(item) { lock.Acquire(); queue.enqueue(item); dataready.signal(); lock.Release(); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T2 Ready queue  NULL … queue add item lock: BUSY (T2) dataready queue T1 T1 (Waiting) T2 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } AddToQueue(item) { lock.Acquire(); queue.enqueue(item); dataready.signal(); lock.Release(); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T2 Ready queue  T1 … queue lock: BUSY (T2) dataready queue NULL T1 (Ready) T2 (Running) signal() wakes up T1 and moves it on ready queue RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } AddToQueue(item) { lock.Acquire(); queue.enqueue(item); dataready.signal(); lock.Release(); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T2 Ready queue  T1, T3 … queue lock: BUSY (T2) dataready queue NULL T1 (Ready) T2 (Running) T3 (Ready) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } AddToQueue(item) { lock.Acquire(); queue.enqueue(item); dataready.signal(); lock.Release(); } RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: Ready queue  T1, T3 … queue lock: FREE dataready queue NULL T1 (Ready) T2 (Terminate) T3 (Ready) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } AddToQueue(item) { lock.Acquire(); queue.enqueue(item); dataready.signal(); lock.Release(); } RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T3 Ready queue  T1 … queue lock: FREE dataready queue NULL T3 scheduled first! T1 (Ready) T3 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T3 Ready queue  T1 … queue lock: BUSY (T3) dataready queue NULL T1 (Ready) T3 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T3 Ready queue  T1 … queue remove item lock: BUSY (T3) dataready queue NULL T1 (Ready) T3 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: Ready queue  T1 … queue lock: FREE dataready queue NULL T1 (Ready) T3 (Finished) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T1 Ready queue  NULL … queue lock: BUSY (T1) dataready queue NULL T1 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); }

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T1 Ready queue  NULL … queue lock: BUSY (T1) dataready queue NULL T1 (Running) RemoveFromQueue() { lock.Acquire(); if (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } ERROR: Nothing in the queue!

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T1 Ready queue  NULL … queue lock: BUSY (T1) dataready queue NULL T1 (Running) RemoveFromQueue() { lock.Acquire(); while (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } Replace “if” with “while”

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T1 Ready queue  NULL … queue lock: BUSY (T1) dataready queue NULL T1 (Ready) RemoveFromQueue() { lock.Acquire(); while (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } Check again if empty!

Mesa Monitor: Why “while()”? CPU State App. Shared State Monitor Running: T1 Ready queue  NULL … queue lock: FREE dataready queue T1 T1 (Waiting) RemoveFromQueue() { lock.Acquire(); while (queue.isEmpty()) { dataready.wait(&lock); } item = queue.dequeue(); lock.Release(); return(item); } http://research.microsoft.com/en-us/um/people/blampson/23-processesinmesa/Acrobat.pdf

Readers/Writers Problem Motivation: Consider a shared database Two classes of users: Readers – never modify database Writers – read and modify database Is using a single lock on the whole database sufficient? Like to have many readers at the same time Only one writer at a time

Basic Readers/Writers Solution Correctness Constraints: Readers can access database when no writers Writers can access database when no readers or writers Only one thread manipulates state variables at a time Basic structure of a solution: Reader() Wait until no writers Access database Check out – wake up a waiting writer Writer() Wait until no active readers or writers Access database Check out – wake up waiting readers or writer State variables (Protected by a lock called “lock”): int AR: Number of active readers; initially = 0 int WR: Number of waiting readers; initially = 0 int AW: Number of active writers; initially = 0 int WW: Number of waiting writers; initially = 0 Condition okToRead = NIL Condition okToWrite = NIL

Code for a Reader Why Release the Lock here? Reader() { // First check self into system lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); // Perform actual read-only access AccessDatabase(ReadOnly); // Now, check out of system lock.Acquire(); AR--; // No longer active if (AR == 0 && WW > 0) // No other active readers okToWrite.signal(); // Wake up one writer lock.release(); } Why Release the Lock here?

Code for a Writer Why Give priority to writers? Writer() { // First check self into system lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock); // Sleep on cond var WW--; // No longer waiting } AW++; // Now we are active! lock.release(); // Perform actual read/write access AccessDatabase(ReadWrite); // Now, check out of system lock.Acquire(); AW--; // No longer active if (WW > 0){ // Give priority to writers okToWrite.signal(); // Wake up one writer } else if (WR > 0) { // Otherwise, wake reader okToRead.broadcast(); // Wake all readers } lock.release(); } Why broadcast() here instead of signal()? Why Give priority to writers?

Simulation of Readers/Writers Solution Use an example to simulate the solution Consider the following sequence of operators: R1, R2, W1, R3 Initially: AR = 0, WR = 0, AW = 0, WW = 0

Simulation of Readers/Writers Solution R1 comes along AR = 0, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R1 comes along AR = 0, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R1 comes along AR = 1, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R1 comes along AR = 1, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R1 comes along AR = 1, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R2 comes along AR = 1, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R2 comes along AR = 1, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R2 comes along AR = 2, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R2 comes along AR = 2, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R2 comes along AR = 2, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); } Assume readers take a while to access database Situation: Locks released, only AR is non-zero

Simulation of Readers/Writers Solution W1 comes along (R1 and R2 are still accessing dbase) AR = 2, WR = 0, AW = 0, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 comes along (R1 and R2 are still accessing dbase) AR = 2, WR = 0, AW = 0, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 comes along (R1 and R2 are still accessing dbase) AR = 2, WR = 0, AW = 0, WW = 1 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 comes along (R1 and R2 are still accessing dbase) AR = 2, WR = 0, AW = 0, WW = 1 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); } W1 cannot start because of readers, so goes to sleep

Simulation of Readers/Writers Solution R3 comes along (R1, R2 accessing dbase, W1 waiting) AR = 2, WR = 0, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R3 comes along (R1, R2 accessing dbase, W1 waiting) AR = 2, WR = 0, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R3 comes along (R1, R2 accessing dbase, W1 waiting) AR = 2, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R3 comes along (R1, R2 accessing dbase, W1 waiting) AR = 2, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); } Status: R1 and R2 still reading W1 and R3 waiting on okToWrite and okToRead, respectively

Simulation of Readers/Writers Solution R2 finishes (R1 accessing dbase, W1, R3 waiting) AR = 2, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R2 finishes (R1 accessing dbase, W1, R3 waiting) AR = 1, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R2 finishes (R1 accessing dbase, W1, R3 waiting) AR = 1, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R2 finishes (R1 accessing dbase, W1, R3 waiting) AR = 1, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R1 finishes (W1, R3 waiting) AR = 1, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R1 finishes (W1, R3 waiting) AR = 0, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R1 finishes (W1, R3 waiting) AR = 0, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R1 finishes (W1, R3 waiting) AR = 0, WR = 1, AW = 0, WW = 1 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); } All reader finished, signal writer – note, R3 still waiting

Simulation of Readers/Writers Solution W1 gets signal (R3 still waiting) AR = 0, WR = 1, AW = 0, WW = 1 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); } Got signal from R1

Simulation of Readers/Writers Solution W1 gets signal (R3 still waiting) AR = 0, WR = 1, AW = 0, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 gets signal (R3 still waiting) AR = 0, WR = 1, AW = 0, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 gets signal (R3 still waiting) AR = 0, WR = 1, AW = 1, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 gets signal (R3 still waiting) AR = 0, WR = 1, AW = 1, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 gets signal (R3 still waiting) AR = 0, WR = 1, AW = 0, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 gets signal (R3 still waiting) AR = 0, WR = 1, AW = 0, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

Simulation of Readers/Writers Solution W1 gets signal (R3 still waiting) AR = 0, WR = 1, AW = 0, WW = 0 Writer() { lock.Acquire(); while ((AW + AR) > 0) { // Is it safe to write? WW++; // No. Active users exist okToWrite.wait(&lock);// Sleep on cond var WW--; // No longer waiting } AW++; lock.release(); AccessDbase(ReadWrite); lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); } No waiting writer, signal reader R3

Simulation of Readers/Writers Solution R3 gets signal AR = 0, WR = 1, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); } Got signal from W1

Simulation of Readers/Writers Solution R3 gets signal AR = 0, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R3 gets signal AR = 0, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R3 gets signal AR = 1, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R3 gets signal AR = 1, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R3 gets signal AR = 1, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Simulation of Readers/Writers Solution R3 gets signal AR = 0, WR = 0, AW = 0, WW = 0 Reader() { lock.Acquire(); while ((AW + WW) > 0) { // Is it safe to read? WR++; // No. Writers exist okToRead.wait(&lock); // Sleep on cond var WR--; // No longer waiting } AR++; // Now we are active! lock.release(); AccessDbase(ReadOnly); lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); } DONE!

Read/Writer Questions Reader() { // check into system lock.Acquire(); while ((AW + WW) > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // read-only access AccessDbase(ReadOnly); // check out of system lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); } Writer() { // check into system lock.Acquire(); while ((AW + AR) > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // read/write access AccessDbase(ReadWrite); // check out of system lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); } What if we remove this line?

Read/Writer Questions Reader() { // check into system lock.Acquire(); while ((AW + WW) > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // read-only access AccessDbase(ReadOnly); // check out of system lock.Acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.broadcast(); lock.release(); } Writer() { // check into system lock.Acquire(); while ((AW + AR) > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // read/write access AccessDbase(ReadWrite); // check out of system lock.Acquire(); AW--; if (WW > 0){ okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); } What if we turn signal to broadcast?

Read/Writer Questions Reader() { // check into system lock.Acquire(); while ((AW + WW) > 0) { WR++; okContinue.wait(&lock); WR--; } AR++; lock.release(); // read-only access AccessDbase(ReadOnly); // check out of system lock.Acquire(); AR--; if (AR == 0 && WW > 0) okContinue.signal(); lock.release(); } Writer() { // check into system lock.Acquire(); while ((AW + AR) > 0) { WW++; okContinue.wait(&lock); WW--; } AW++; lock.release(); // read/write access AccessDbase(ReadWrite); // check out of system lock.Acquire(); AW--; if (WW > 0){ okContinue.signal(); } else if (WR > 0) { okContinue.broadcast(); } lock.release(); } What if we turn okToWrite and okToRead into okContinue?

Read/Writer Questions Reader() { // check into system lock.Acquire(); while ((AW + WW) > 0) { WR++; okContinue.wait(&lock); WR--; } AR++; lock.release(); // read-only access AccessDbase(ReadOnly); // check out of system lock.Acquire(); AR--; if (AR == 0 && WW > 0) okContinue.signal(); lock.release(); } Writer() { // check into system lock.Acquire(); while ((AW + AR) > 0) { WW++; okContinue.wait(&lock); WW--; } AW++; lock.release(); // read/write access AccessDbase(ReadWrite); // check out of system lock.Acquire(); AW--; if (WW > 0){ okContinue.signal(); } else if (WR > 0) { okContinue.broadcast(); } lock.release(); } R1 arrives W1, R2 arrive while R1 still reading  W1 and R2 wait for R1 to finish R1 signals R2

Read/Writer Questions Reader() { // check into system lock.Acquire(); while ((AW + WW) > 0) { WR++; okContinue.wait(&lock); WR--; } AR++; lock.release(); // read-only access AccessDbase(ReadOnly); // check out of system lock.Acquire(); AR--; if (AR == 0 && WW > 0) okContinue.broadcast(); lock.release(); } Writer() { // check into system lock.Acquire(); while ((AW + AR) > 0) { WW++; okContinue.wait(&lock); WW--; } AW++; lock.release(); // read/write access AccessDbase(ReadWrite); // check out of system lock.Acquire(); AW--; if (WW > 0){ okContinue.broadcast(); } else if (WR > 0) { okContinue.broadcast(); } lock.release(); } Need to change to broadcast! Need to change to broadcast!

Administrivia Project 1 design document due Thu 2/13 at 11:59pm No slip days can be used

5min Break

Tips for Programming in a Project Team Big projects require more than one person (or long, long, long time) Big OS: thousands of person-years! It’s very hard to make software project teams work correctly Doesn’t seem to be as true of big construction projects Empire state building finished in one year: staging iron production thousands of miles away Or the Hoover dam: built towns to hold workers “You just have to get your synchronization right!”

Big Projects What is a big project? Time/work estimation is hard Programmers are eternal optimistics (it will only take two days)! This is why we bug you about starting the project early Can a project be efficiently partitioned? Partitionable task decreases in time as you add people But, if you require communication: Time reaches a minimum bound With complex interactions, time increases! Mythical person-month problem: You estimate how long a project will take Starts to fall behind, so you add more people Project takes even more time!

Techniques for Partitioning Tasks Functional Person A implements threads, Person B implements semaphores, Person C implements locks… Problem: Lots of communication across APIs If B changes the API, A may need to make changes Story: Large airline company spent $200 million on a new scheduling and booking system. Two teams “working together.” After two years, went to merge software. Failed! Interfaces had changed (documented, but no one noticed). Result: would cost another $200 million to fix. Task Person A designs, Person B writes code, Person C tests May be difficult to find right balance, but can focus on each person’s strengths (Theory vs systems hacker) Since Debugging is hard, Microsoft has two testers for each programmer Most CS162 project teams are functional, but people have had success with task-based divisions [poll]

Communication More people mean more communication Changes have to be propagated to more people Think about person writing code for most fundamental component of system: everyone depends on them! Miscommunication is common “Index starts at 0? I thought you said 1!” Who makes decisions? [poll] Individual decisions are fast but trouble Group decisions take time Centralized decisions require a big picture view (someone who can be the “system architect”) Often designating someone as the system architect can be a good thing Better not be clueless Better have good people skills Better let other people do work

Coordination More people  no one can make all meetings! They miss decisions and associated discussion Example from earlier class: one person missed meetings and did something group had rejected Why do we limit groups to 5 people? You would never be able to schedule meetings otherwise Why do we require 4 people minimum? You need to experience groups to get ready for real world People have different work styles Some people work in the morning, some at night How do you decide when to meet or work together? What about project slippage? It will happen, guaranteed! Ex: everyone busy but not talking. One person way behind. No one knew until very end – too late! Hard to add people to existing group Members have already figured out how to work together

How to Make it Work? People are human. Get over it. People will make mistakes, miss meetings, miss deadlines, etc. You need to live with it and adapt It is better to anticipate problems than clean up afterwards. Document, document, document Why Document? Expose decisions and communicate to others Easier to spot mistakes early Easier to estimate progress What to document? Everything (but don’t overwhelm people or no one will read) Standardize! One programming format: variable naming conventions, tab indents,etc. Comments (Requires, effects, modifies)—javadoc?

Suggested Documents for You to Maintain Project objectives: goals, constraints, and priorities Specifications: the manual plus performance specs This should be the first document generated and the last one finished Meeting notes Document all decisions You can often cut & paste for the design documents Schedule: What is your anticipated timing? This document is critical! Organizational Chart Who is responsible for what task?

Use Software Tools Source revision control software (git, SVN, CVS) Easy to go back and see history Figure out where and why a bug got introduced Communicates changes to everyone (use RCS’s features) Use an Integrated Development Environment Structured development model (e.g., Eclipse IDE) Use automated testing tools Write scripts for non-interactive software Use “expect” for interactive software Microsoft rebuilt Vista – Win8 kernels every night with the day’s changes. Everyone ran/tested the latest software Use E-mail and instant messaging consistently to leave a history trail

Test Continuously Integration tests all the time, not at 11pm on due date! Write dummy stubs with simple functionality Let’s people test continuously, but more work Schedule periodic integration tests Get everyone in the same room, check out code, build, and test. Don’t wait until it is too late! Testing types: Unit tests: white-/black-box check each module in isolation (use JUnit?) Daemons: subject code to exceptional cases Random testing: Subject code to random timing changes Automated testing and building: http://jenkins-ci.org/ Test early, test later, test again Tendency is to test once and forget; what if something changes in some other part of the code?

Conclusions Monitors, and Condition Variables Higher level constructs that are harder to “screw up” Important to follow a good process Document everything Use software tools Test continuously