750 likes | 879 Views
Chapter 9: High-Level Synchronization. Prof. Steven A. Demurjian, Sr. † Computer Science & Engineering Department The University of Connecticut 191 Auditorium Road, Box U-155 Storrs, CT 06269-3155. steve@engr.uconn.edu http://www.engr.uconn.edu/~steve (860) 486 - 4818.
E N D
Chapter 9: High-Level Synchronization Prof. Steven A. Demurjian, Sr. † Computer Science & Engineering Department The University of Connecticut 191 Auditorium Road, Box U-155 Storrs, CT 06269-3155 steve@engr.uconn.edu http://www.engr.uconn.edu/~steve (860) 486 - 4818 † These slides have been modified from a set of originals by Dr. Gary Nutt.
Purpose of this Chapter • Semaphores as Presented in Chapter 8, Provide a Solution Venue for Limited Domain of Problems • Other Available Synchronization Primitives • AND Synchronization (Simultaneous P & V) • Event Handling • Monitors: ADTs for Synchronization • All Techniques Offer • Primitives for Software Engineers • OS/Programming Level Solutions • Less “Rigorous” Approach is IPC • Inter-process Communication • Pipes, Mailboxes, Shared Memory, etc.
Recall: Process Manager Overview Process Process Process Abstract Computing Environment Synchronization Process Description File Manager Protection Deadlock Process Manager Device Manager Memory Manager Resource Manager Resource Manager Scheduler Resource Manager Devices Memory CPU Other H/W
Dining Philosophers • Philosophers Think and Ignore Food • When They Want to Eat, Need Two Forks • Pick Up One and Then Another • How Do We Prevent Two Philosophers Holding Same Fork at Same Time? • What is a Synchronization Scheme for the Problem? while(TRUE) { think(); eat(); }
Dining Philosophers Is Semaphore Solution Correct? philosopher(int i) { while(TRUE) { // Think // Eat P(fork[i]); P(fork[(i+1) mod 5]); eat(); V(fork[(i+1) mod 5]); V(fork[i]); } } semaphore fork[5]=(1,1,1,1,1); fork(philosopher, 1, 0); fork(philosopher, 1, 1); fork(philosopher, 1, 2); fork(philosopher, 1, 3); fork(philosopher, 1, 4);
Dining Philosophers A Correct Semaphore Solution philosopher(int i) { while(TRUE) { // Think // Eat j = i % 2; P(fork[(i+j) mod 5]); P(fork[(i+1-j) mod 5]); eat(); V(fork[(i+1-j) mod 5]); V(fork[[(i+j) mod 5] ); } } semaphore fork[5]=(1,1,1,1,1); fork(philosopher, 1, 0); fork(philosopher, 1, 1); fork(philosopher, 1, 2); fork(philosopher, 1, 3); fork(philosopher, 1, 4);
AND Synchronization • Suppose Multiple Processes Need Access to Two Resources, R1 and R2 • Some Processes Access R1 • Some Processes Access R2, • Some Processes Need Both • How are Resources and Process Requests Ordered to Insure Deadlock Avoidance? • Define a Simultaneous P Able to Access All Semaphores at Same Time • Psimultaneous(S1, …, Sn)
AND SynchronizationExample semaphore mutex = 1; semaphore block = 0; P.sim(int S, int R) { P(mutex); S--; R--; if((S < 0) || (R < 0)) { V(mutex); P(block); } else V(mutex); } V.sim(int S, int R) { P(mutex); S++; R++; if(((S >= 0) && (R >= 0)) && ((S == 0) || (R == 0))) V(block); V(mutex); }
Dining Philosophers Problem philosopher(int i) { while(TRUE) { // Think // Eat Psimultaneous(fork[i], fork [(i+1) mod 5]); eat(); Vsimultaneous(fork[i], fork [(i+1) mod 5]); } } semaphore fork[5] = (1,1,1,1,1); fork(philosopher, 1, 0); fork(philosopher, 1, 1); fork(philosopher, 1, 2); fork(philosopher, 1, 3); fork(philosopher, 1, 4);
Events • Denote Many Different Things in Each OS • Used Throughout an OS to Trap • Keyboard Input and Mouse Action/Location • GUI: Event Driven Based on Input (KB, M) • Processes Can Wait on an Event Until Another Process Signals the Event • GUI Can Wait Until State of Input (KB, M,etc.) Dictates Next “Operation” to Invoke • Processes are Self-Blocking During Wait • Event Handling is Active, Since Process Takes Responsibility for Blocking and Reawakening
Events • Events Tracked via Event Descriptor (“Event Control Block”) and wait and signal Operations • Active Approach (Self Interrupts) • Multiple Processes Can Wait on an Event • Exactly One Process is Unblocked When a Signal Occurs • A Signal With No Waiting Process is Ignored • Passive Approach • Waiting Processes Responsible for Detecting Signal • May Have a Queue Function that Returns the Number of Processes Waiting on the Event
Example class Event { . . . public: void signal(); void wait() int queue(); } shared Event topOfHour; . . . // Wait until the top of the hour before proceding topOfHour.wait(); // It’s the top of the hour ... shared Event topOfHour; . . . while(TRUE) if(isTopOfHour()) while(topOfHour.queue() > 0) topOfHour.signal(); } . . .
UNIX Signals • A UNIX Signal Corresponds to an Event • Raised by One Process (or Hardware) to Call Another Process’s Attention to an Event • Caught (or Ignored) by the Subject Process • Justification for Including Signals Was for the OS to Inform a User Process of an Event • User Pressed Delete Key • Program Tried to Divide by Zero • Attempt to Write to a Nonexistent Pipe • Etc. • What are Signals Similar to? Exception Handling at Programming Level!!
More on Signals • Each Version of UNIX Has a Fixed Set of Signals (Linux Has 31 of Them) • signal.h Defines the Signals in the OS • Application Programs Can Use SIGUSR1 & SIGUSR2 for Arbitrary Signaling • Raise a Signal With kill(pid, signal) • Process Can • Let Default Handler Catch the Signal, • Catch the Signal With Own Code, or • Cause the Signal to Be Ignored
Signals in Sun Unix #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt (rubout) */ #define SIGQUIT 3 /* quit (ASCII FS) */ #define SIGILL 4 /* illegal instruction (not reset when caught)*/ #define SIGTRAP 5 /* trace trap (not reset when caught) */ #define SIGIOT 6 /* IOT instruction */ #define SIGABRT 6 /* used by abort, replace SIGIOT in the future*/ #define SIGEMT 7 /* EMT instruction */ #define SIGFPE 8 /* floating point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGBUS 10 /* bus error */ #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ #define SIGPIPE 13 /* write on a pipe with no one to read it */ #define SIGALRM 14 /* alarm clock */ #define SIGTERM 15 /* software termination signal from kill */ #define SIGUSR1 16 /* user defined signal 1 */ #define SIGUSR2 17 /* user defined signal 2 */
Signals in Sun Unix #define SIGCLD 18 /* child status change */ #define SIGCHLD 18 /* child status change alias (POSIX) */ #define SIGPWR 19 /* power-fail restart */ #define SIGWINCH 20 /* window size change */ #define SIGURG 21 /* urgent socket condition */ #define SIGPOLL 22 /* pollable event occured */ #define SIGIO SIGPOLL /* socket I/O possible (SIGPOLL alias) */ #define SIGSTOP 23 /* stop (cannot be caught or ignored) */ #define SIGTSTP 24 /* user stop requested from tty */ #define SIGCONT 25 /* stopped process has been continued */ #define SIGTTIN 26 /* background tty read attempted */ #define SIGTTOU 27 /* background tty write attempted */ #define SIGVTALRM 28 /* virtual timer expired */ #define SIGPROF 29 /* profiling timer expired */ #define SIGXCPU 30 /* exceeded cpu limit */ #define SIGXFSZ 31 /* exceeded file size limit */ #define SIGWAITING 32 /* process's lwps are blocked */ #define SIGLWP 33 /* special signal used by thread library */
More on Signals (Continued) • OS Signal System Call • To Ignore: Signal(sig#, SIG_IGN) • To Reinstate Default: Signal(sig#, SIG_DFL) • To Catch: Signal(sig#, Myhandler) • Provides a Facility for Writing Your Own Event Handlers in the Style of Interrupt Handlers
Signal Handling /* code for process p . . . signal(SIG#, sig_hndlr); . . . /* ARBITRARY CODE */ void sig_hndlr(...) { /* ARBITRARY CODE */ } An Executing Process, q Raise “SIG#” for “p” sig_hndlr runs in p’s address space q is Blocked q Resumes Execution See Detailed Code for Signaling in Unix in Figure 9.4
Event Objects in NT • An Event Object Announces Occurrence of “Something” in One Thread that Needs to be Known in Other Threads • Visibility of Event via: • Event Signal Seen by only one Thread • Event Signal may be Seen by Multiple Threads • Thus, • One Event Object May Signal One Thread • One Event Object May Signal Many Threads • Many Event Object May Signal Same Thread
NT Events Thread • Signaled • Implicitly • Manually • Callbacks WaitForSingleObject(foo, time); Signaled/Not Signaled Flag Kernel object Waitable timer
NT Events Thread Thread Thread WaitForSingleObject(foo, time); WaitForSingleObject(foo, time); WaitForSingleObject(foo, time);
NT Events Thread WaitForMultipleObjects(foo, time);
Events and Event Handling in Java • Events and Event Handling in Java are Integral to Correct Operation of GUIs using AWT • Event Handling in Java is … • Detecting and Processing User Inputs • Events Include Keyboard, Mouse Clicks, etc. • Events Such as Value and Screen Appearance Changes also Possible • Event Handling Code Critical for Useful Applications • Solutions Must be Structured Around Specific Event Processing Model of Computation • See http://java.sun.com/docs/books/tutorial/uiswing/events/index.html
The Java 1.1 Event Model • Contrast with MS-Windows and X • Event Model was Able to Handle Flood of Events Recorded from Different Places • Ability to Process Flood of Events • Events Processed Through a Giant ‘Switch’ Statement • Advantage/Disadvantage • Easy to Implement/Hard to Evolve • Use of a Switch Statement Implies a Decidedly Non-OO Design • What is Another Alternative?
The Java 1.1 Event Model • Contrast with Microsoft Foundation Classes Programming Model or Motif Programming Model • Each Component Must Be Over-Ridden to Make It Do What You Want It to Do • Something Similar to the Older Java 1.0 Inheritance Event Model • This Approach is More Object-Oriented, But Involves a Great Deal of Work • Inheritance Model Can Limit Flexibility and Power, since Java Doesn’t Support Multiple Inheritance • Recall a Java Class May Implement Multiple Interfaces but only Extend a Single Class
The Java 1.1 Event Model • In the New Java 1.1 Delegation Event Model • More Specificity in Controlling Events Based on Individual Components • A Component Can Defined as Follows • Identify Which Events are to be Handled by Each Component at Design/Implementation Level • At Runtime, Component Knows Which Object or Objects Should Be Notified When the Component Generates a Particular Type of Event • If a Component is Not Interested in an Event Type • Then Events of That Type Will Not Be Propagated • That is, Component can Ignore Certain Events
The Java 1.1 Event Model (According to Sun) • Simple and Easy to Learn • Support a Clean Separation Between Application and GUI Code • Flexible Enough to Enable Varied Application Models for Event Flow and Propagation • For Visual Tool Builders, Enable Run-time Discovery of Both Events That a Component Generates as Well as the Events It May Observe • Support Backward Binary Compatibility With the Old Model (Java 1.0 Inheritance Event Model) • Facilitate the Creation of Robust Event Handling Code Which is Less Error-prone (Strong Compile-time Checking)
Java’s 1.1 Delegation Event Model Event Listener and Event Source • Event Listener: Any Object Interested in Receiving Messages (or Events) • Entity That Desires Notification When an Event Happens • Receives the Specific Eventobject Subclass as a Parameter • Event Source: Any Object That Generates These Messages (or Events) • Defines When and Where an Event Will Happen • Hireevent and Hirelistener are Required for an Event Source to Function • Sends Notification to Registered Classes When the Event Happens
Types of Events • ActionEvent Generated by Component Activation • AdjustmentEvent Generated by Adjustment of Adjustable Components Such as Scroll Bars • ContainerEvent Generated When Components are Added to or Removed From a Container • FocusEvent Generated When a Component Receives Input Focus • ItemEvent Generated When an Item is Selected From a List, Choice or Check Box • KeyEvent Generated by Keyboard Activity • MouseEvent Generated by Mouse Activity • PaintEvent Generated When a Component is Painted • TextEvent Generated When a Text Component is Modified • WindowEvent Generated by Window Activity Like Minimizing or Maximizing
The 1.1 Delegation Event Model • Event Source Object Maintains Listeners List Who are Interested in Receiving Events that It Produces • Event Source Object Provides Methods That Allow the Listeners to • Add Themselves ( ‘Register’ ) to This List of ‘Interested’ Objects • Remove Themselves From This List of ‘Interested’ Objects. • Event Source Object Notifies All the Listeners That the Event Has Occurred • When Event Source Object Generates an Event • When User Input Event Occurs on the Event Source Object
Event Object Interactions • An Event Source Object Notifies an Event Listener Object by • Invoking a Method on Listener Object • Passing Listener Object an EventObject • In Order for the Event Source Object to Invoke a Method on a Listener • All Listeners Must Implement the Required Method • Guaranteed by Requiring All Event Listeners for a Particular Type of Event Implement a Corresponding Interface
Example: Event for Employee’s Hire Date public class HireEvent extends EventObject { private long hireDate; public HireEvent (Object source) { super (source); hireDate = System.currentTimeMillis(); } public HireEvent (Object source, long hired) { super (source); hireDate = hired; } public long getHireDate () { return hireDate; } }
Event Listeners • Event Listeners are Objects That Are Responsible for Handling a Particular Task of a Component • Event Listener Typically Implements a Java Interface That Contains Event-Handling Code for a Particular Component • Standard Pattern for Giving Listener to Component • Create a Listener Class That Implements the Corresponding Listener Interface • Construct the Component • Construct an Instance of the Listener Interface • Call Add...Listener() on the Component, Passing in the Listener
The EventListener Interface • Eventlistener Interface • Empty Interface • Acts as a Tagging Interface That All Event Listeners Must Extend • Eventtypelistener Name of Listener Interface • The Name for the New Hireevent Listener Would Be Hirelistener • Method Names Should Describe the Event Happening • Code public interface HireListener extends java.util.EventListener { public abstract void hired (HireEvent e); }
EventSource Interface Methods • Registration Process Method Patterns public synchronized void addListenerType(ListenerType l); public synchronized void removeListenerType(ListenerType l); • Maintaining Eventsource Code private Vector hireListeners = new Vector(); public synchronized void addHireListener(HireListener l) { hireListeners.addElement (l); } public synchronized void removeHireListener (HireListener l) { hireListeners.removeElement (l); }
EventSource: Hiring Example protected void notifyHired () { vector l; // Create Event HireEvent h = new HireEvent (this); // Copy listener vector so it won't change while firing synchronized (this) { l = (Vector)hireListeners.clone(); } for (int i=0;i<l.size();i++) { HireListener hl = (HireListener)l.elementAt (i); hl.hired(h); } }
Monitors • Specialized Form of ADT • Encapsulates Implementation • Public Interface (Types & Functions) • Only One Process Can Be Executing (Invoking a Method) in the ADT at a Time • One Shared Instance of ADT! monitor anADT { semaphore mutex = 1; // Implicit . . . public: proc_i(…) { P(mutex); // Implicit <processing for proc_i>; V(mutex); // Implicit }; . . . };
Example: Shared Balance • Consider the Shared Balance Monitor Below. • Each Method (credit/debit) Define Critical Section • Hence, by its Definition … • Methods Disable Interrupts at Start of Call and • Re-enable Interrupts at End of Call monitor sharedBalance { double balance; public: credit(double amount) {balance += amount;}; debit(double amount) {balance -= amount;}; . . . };
Example: Readers & Writers monitor readerWriter_1 { int numberOfReaders = 0; int numberOfWriters = 0; boolean busy = FALSE; public: startRead() { }; finishRead() { }; startWrite() { }; finishWrite() { }; }; reader(){ while(TRUE) { . . . startRead(); finishRead(); . . . } fork(reader, 0); . . . fork(reader, 0): fork(writer, 0); . . . fork(writer, 0); writer(){ while(TRUE) { . . . startWrite(); finishWrite(); . . . }
Example: Readers & Writers monitor readerWriter_1 { int numberOfReaders = 0; int numberOfWriters = 0; boolean busy = FALSE; public: startRead() { while(numberOfWriters != 0) ; numberOfReaders++; }; finishRead() { numberOfReaders-; }; startWrite() { numberOfWriters++; while( busy || (numberOfReaders > 0) ) ; busy = TRUE; }; finishWrite() { numberOfWriters--; busy = FALSE; }; };
Example: Readers & Writers monitor readerWriter_1 { int numberOfReaders = 0; int numberOfWriters = 0; boolean busy = FALSE; public: startRead() { while(numberOfWriters != 0); numberOfReaders++; }; finishRead() { numberOfReaders--; }; startWrite() { numberOfWriters++; while( busy || (numberOfReaders > 0) ) ; busy = TRUE; }; finishWrite() { numberOfWriters--; busy = FALSE; }; }; • Deadlock can Occur!
Further Monitor Execution Semantics • Recall that in P Operation for Semaphore, Wait Gives Opportunity to Interrupt • Suppose Process Obtains Monitor • Then, Monitor Detects a Condition for Which it Needs to Wait • Since Only One Process Using Monitor at Any One Time, Other Processes Wait Forever • Need Special Mechanism to Suspend Process Until Condition is Met, Then Resume • Process That Makes Condition TRUE Must Exit Monitor • Suspended Process Must be Able to Resume • Introduce Concept of Condition Variable
Condition Variables • Essentially an Event (As Defined Previously) • Global Condition Visible to All Methods Defined in Monitor -- Occurs Only Inside a Monitor • Operations to Manipulate Condition Variable • Wait: Suspend Invoking Process Until Another Executes a Signal • Signal: Resume One Process If Any Are Suspended, Otherwise Do Nothing • Queue: Return TRUE If There is at Least One Process Suspended on the Condition Variable • Conditions Increase Complexity of Monitor • Transcends Traditional Semaphore Capabilities
Active vs. Passive Signal • Hoare Semantics: Same as Active Semaphore • p0 Executes Signal while p1 is Waiting p0 Yields the Monitor to p1 • The Signal is only TRUE the Instant it Happens • p0 Generates Self Interrupt for p1 • Brinch Hansen (“Mesa”) Semantics: Same as Passive Semaphore • p0 Executes Signal while p1 is Waiting p0 Continues to Execute • When p0 exits the Monitor p1 can Receive the Signal • p0 Responsible for Receiving Signal • Used in the Xerox Mesa Implementation
Hoare vs. Mesa Semantics • Hoare semantics: . . . if(resourceNotAvailable()) resourceCondition.wait(); /* now available … continue … */ . . . • Mesa semantics: . . . while(resourceNotAvailable()) resourceCondition.wait(); /* now available … continue … */ . . .
Second Try at Readers & Writers monitor readerWriter_2 { int numberOfReaders = 0; boolean busy = FALSE; condition okToRead, okToWrite; public: // startRead and finishRead used by Readers startRead() { if(busy || // busy = TRUE implies writer (okToWrite.queue()) okToRead.wait(); numberOfReaders++; okToRead.signal(); }; finishRead() { numberOfReaders--; if(numberOfReaders == 0) okToWrite.signal(); };
Second Try at Readers & Writers // startWrite and finishWrite Used by Writers startWrite() { if((numberOfReaders != 0) || busy) okToWrite.wait(); busy = TRUE; }; finishWrite() { busy = FALSE; if(okToRead.queue()) okToRead.signal() else okToWrite.signal() }; }; Each Method is Atomic! Cannot be Interrupted!
Example: Synchronizing Traffic • One-Way Tunnel • Can Only Use Tunnel If No Oncoming Traffic • OK to Use Tunnel If Traffic is Already Flowing the Right Way • Differentiate Between Northbound and Southbound Traffic • Reset Light from Red to Green (and Green to Red) to Control Flow