Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication...
Content <ul><li>Motivation </li></ul><ul><li>Shared Memory Methods  </li></ul><ul><ul><li>Monitors  </li></ul></ul><ul><ul...
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication...
Motivation <ul><li>Semaphores and Events </li></ul><ul><ul><li>Powerful but  low-level  abstractions </li></ul></ul><ul><u...
Solutions <ul><li>High-level  share memory  models </li></ul><ul><ul><li>Monitors  </li></ul></ul><ul><ul><li>Protected Ty...
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication...
Monitors <ul><li>Higher level  construct than  semaphores . </li></ul><ul><li>A package of grouped procedures, variables a...
The Monitor Abstraction Shared  among processes Processes  cannot  access them directly wait/signal  primitives for proces...
Example: Queue Handler Queue AddToQueue RemoveFromQueue
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Process Synchronization <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul...
Condition Variables <ul><li>Monitors need more facilities than just mutual exclusion. Need some way to  wait . </li></ul><...
Variations on  Semantics <ul><li>Hoare semantics:  awakened process gets monitor lock immediately. </li></ul><ul><ul><li>P...
More on Condition Variables <ul><li>“ Condition variable”  c  is  not  a conventional variable </li></ul><ul><ul><li>c  ha...
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Hoare Monitors <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul><li>cond...
Example: Bounded Buffer Deposit Remove . . . . . . . . . 0 1 2 n  1 n  2
Example: Bounded Buffer Deposit Remove . . . . . . . . . 0 1 2 n  1 n  2 . . . nextin nextout count
Example: Bounded Buffer Deposit Remove count nextout nextin
Example: Bounded Buffer <ul><li>monitor  BoundedBuffer  {  </li></ul><ul><ul><li>char buffer[n];  </li></ul></ul><ul><ul><...
Priority Waits <ul><li>Hoare monitor signal  resumes longest waiting process . </li></ul><ul><li>Not always what one wants...
Example: Alarm Clock 0 1 3 2 4 5 . . . The  current time  ( now ) of the alarm clock is increased  periodically  ( tick )....
Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) Call at time 150
Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) p2: . . . AlarmClock.Wakeme(150); . . . ...
Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) p2: . . . AlarmClock.Wakeme(150); . . . ...
Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) p2: . . . AlarmClock.Wakeme(150); . . . ...
Example: Alarm Clock <ul><li>monitor  AlarmClock  {  </li></ul><ul><li>int now=0;  </li></ul><ul><li>condition  wakeup ;  ...
Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) p2: . . . AlarmClock.Wakeme(150); . . . ...
Mesa and Java Monitors <ul><li>notify   is a variant of  signal </li></ul><ul><li>After  c.notify : </li></ul><ul><ul><li>...
Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . ....
Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . ....
Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . ....
Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . ....
Solution P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . . . . . B1=FASL...
Example: Queue Handler Queue AddToQueue RemoveFromQueue
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Example: Queue Handler <ul><li>monitor  QueueHandler { </li></ul><ul><ul><li>struct Queue  queue ; </li></ul></ul><ul><ul>...
Protected Types <ul><li>Special case of monitor where: </li></ul><ul><ul><li>c.wait  is the  first  operation of a procedu...
Example: Bounded Buffer <ul><li>Protected  body BoundedBuffer { </li></ul><ul><li>char buffer[n]; </li></ul><ul><li>int ne...
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication...
Distributed Synchronization <ul><li>Semaphore-based primitive </li></ul><ul><ul><li>Requires  Shared Memory </li></ul></ul...
Questions of  Send/Receive <ul><li>Does  sender   wait  for message to be accepted? </li></ul><ul><li>Does  receiver   wai...
Types of  Send/Receive broadcast message  m broadcast message  m wait until accepted implicit naming send message  m  to r...
Types of  Send/Receive broadcast message  m broadcast message  m wait until accepted implicit naming send message  m  to r...
Types of  Send/Receive Little practical used Little practical used Little practical used    no use, e.g., Some  debugging...
Process Coordination Little practical used Little practical used Solving a variety of process coordination problems. broad...
Example:Printer Sever Little practical used Little practical used broadcast message  m broadcast message  m wait until acc...
Implementation for Asynchronous Operations Little practical used Little practical used built-in buffers are required to ho...
Channels, Ports, and Mailboxes <ul><li>Allow  indirect  communication: </li></ul><ul><ul><li>Senders/Receivers name  chann...
Named Message Channels Named Pipe (Win32) P1: . . . . . . . . send(ch1, msg1); . . . . . . . . P2: . . . . . . . . send(ch...
CSP/Occam <ul><li>Using  Named channel , say,  ch1  to connect processes, say,  p1  and  p2 </li></ul><ul><ul><li>p1  send...
Bounded buffer with CSP <ul><li>Communicating Sequential Processes: </li></ul><ul><ul><li>Buffer  B </li></ul></ul><ul><ul...
Bounded buffer with CSP Buffer Producer Consumer deposit request remove
Bounded buffer with CSP Buffer Producer Consumer deposit request remove send(deposit, data) send(request) receive(remove,d...
Bounded buffer with CSP Buffer Producer Consumer deposit request remove receive(request) send(remove,data) receive(deposit...
Bounded buffer with CSP <ul><li>process BoundedBuffer {  </li></ul><ul><li>char buf[n]; </li></ul><ul><li>int nextin=0, ne...
Bounded buffer with CSP <ul><li>process BoundedBuffer {  </li></ul><ul><li>char buf[n]; </li></ul><ul><li>int nextin=0, ne...
Bounded buffer with CSP <ul><li>process BoundedBuffer {  </li></ul><ul><li>char buf[n]; </li></ul><ul><li>int nextin=0, ne...
More on Named Channels <ul><li>Each  named channel  serves for a  particular purpose . </li></ul><ul><li>Processes  are  c...
Ports and Mailboxes Port Mailboxes
Ports and Mailboxes <ul><li>Processes are connected through  intermediary . </li></ul><ul><ul><li>Allowing a receiver to  ...
Ports and Mailboxes
Procedure-Based Communication <ul><li>Send/Receive  are too  low  level (like  P/V ) </li></ul><ul><li>Typical interaction...
Procedure-Based Communication <ul><li>Send/Receive  are too  low  level (like  P/V ) </li></ul><ul><li>Typical interaction...
RPC <ul><li>Caller issues:  res = f( params ) </li></ul><ul><li>This is translated into: </li></ul>res = f( params ) // ca...
Rendezvous <ul><li>With  RPC :  </li></ul><ul><ul><li>Called process  p  is part of a dedicated  server </li></ul></ul><ul...
Rendezvous Caller Server q . f ( param ) accept  f ( param ) S Similar syntax/semantics to  RPC Name of the  remote proces...
Semantics of a Rendezvous <ul><li>Caller or Server  waits  for  the other . </li></ul><ul><li>Then, they execute in  paral...
Semantics of a Rendezvous p q Rendezvous p q Rendezvous q . f () accept  f () S q . f () accept  f () S
Rendezvous: Selective Accept <ul><ul><ul><li>select { </li></ul></ul></ul><ul><ul><ul><li>[when B1:]  accept  E1 (…) S1; <...
Rendezvous: Selective Accept [. . .] : optional <ul><ul><ul><li>select { </li></ul></ul></ul><ul><ul><ul><li>[when B1:]  a...
Example: Bounded Buffer <ul><ul><ul><li>process  BoundedBuffer  { </li></ul></ul></ul><ul><ul><ul><li>char buffer[n]; </li...
Example: Bounded Buffer <ul><ul><ul><li>process  BoundedBuffer  { </li></ul></ul></ul><ul><ul><ul><li>char buffer[n]; </li...
Example: Bounded Buffer BoundedBuffer .deposit(data) BoundedBuffer .remove(data)
Distributed Mutual Exclusion <ul><li>CS  problem in a Distributed Environment </li></ul><ul><ul><li>No   shared memory ,  ...
Distributed Mutual Exclusion with  Token Ring A practical and elegant compromise version of fully distributed approach.
Distributed Mutual Exclusion with  Token Ring Controler[2]: P[2]: CS2; Program2; Controler[3]: P[3]: CS3; Program3; Contro...
Distributed Mutual Exclusion with  Token Ring Controler[2]: P[2]: CS2; Program2; Controler[3]: P[3]: CS3; Program3; Contro...
Distributed Mutual Exclusion with  Token Ring Controler[2]: P[2]: CS2; Program2; Controler[3]: P[3]: CS3; Program3; Contro...
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication...
Readers/Writers Problem Database
Readers/Writers Problem Database Writers can work only when  no   reader  activated. One Writer can work at a time.
Readers/Writers Problem Database Readers can work only when  no   writer  activated. Allows infinite number of readers.
Readers/Writers Problem <ul><li>Extension  of basic CS problem </li></ul><ul><ul><li>(Courtois, Heymans, and Parnas, 1971)...
Solution Using Monitor monitor  Readers_Writers  {  int readCount=0, writing=0; condition OK_R, OK_W; start_read()  {  if ...
Solution Using Monitor monitor  Readers_Writers  {  int readCount=0, writing=0; condition OK_R, OK_W; start_read()  {  if ...
Dining Philosophers
Dining Philosophers <ul><li>Five philosophers  sit around a circular table.  </li></ul><ul><li>In the centre of the table ...
Dining Philosophers p 1 p 2 p 3 p 4 p 5 f 1 f 2 f 3 f 4 f 5 p(i) { while (1) { think(i); grab_forks (i); eat(i); return_fo...
Solutions to deadlock <ul><li>Use a  counter : </li></ul><ul><ul><li>At most   n    1  philosophers may attempt to grab f...
Logical Clocks <ul><li>Many applications need to  time-stamp  events  </li></ul><ul><ul><li>for  debugging , recovery, dis...
The Problem of Clock Skewness File User  (U) File Server  (FS) e 1 e 2 e 3 e 4 C U C FS send send receive receive delta 1 ...
Logical Clocks e i e s e k e r send receive p 1 p 2 e j
Logical Clocks in Action u v x y 4 5 13 15 6 14
The Elevator Algorithm <ul><li>The simple algorithm by which a single elevator can  decide  where to stop  is: </li></ul><...
The Elevator Algorithm
The Elevator Algorithm <ul><li>Pressing button  at floor  i  or button   i  inside elevator invokes:  request(i) </li></ul...
The Elevator Algorithm Using Priority Waits monitor elevator {  int dir=1, up=1, down=-1, pos=1, busy=0; condition  upswee...
The Elevator Algorithm Using Priority Waits monitor elevator {  int dir=1, up=1, down=-1, pos=1, busy=0; condition  upswee...
The Elevator Algorithm Using Priority Waits monitor elevator {  int dir=1, up=1, down=-1, pos=1, busy=0; condition upsweep...
Upcoming SlideShare
Loading in …5
×

Os3 2

680 views
650 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
680
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
4
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Os3 2

  1. 1. Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication 主講人:虞台文
  2. 2. Content <ul><li>Motivation </li></ul><ul><li>Shared Memory Methods </li></ul><ul><ul><li>Monitors </li></ul></ul><ul><ul><li>Protected Types </li></ul></ul><ul><li>Distributed Synchronization/Communication </li></ul><ul><ul><li>Message-Based Communication </li></ul></ul><ul><ul><li>Procedure-Based Communication </li></ul></ul><ul><ul><li>Distributed Mutual Exclusion </li></ul></ul><ul><li>Other Classical Problems </li></ul><ul><ul><li>The Readers/Writers Problem </li></ul></ul><ul><ul><li>The Dining Philosophers Problem </li></ul></ul><ul><ul><li>The Elevator Algorithm </li></ul></ul><ul><ul><li>Event Ordering with Logical Clocks </li></ul></ul>
  3. 3. Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication Motivation
  4. 4. Motivation <ul><li>Semaphores and Events </li></ul><ul><ul><li>Powerful but low-level abstractions </li></ul></ul><ul><ul><ul><li>Such programs are difficult to design, debug, and maintain </li></ul></ul></ul><ul><ul><ul><li>Programming with them is highly error prone , e.g., deadlock </li></ul></ul></ul><ul><ul><li>Insecure for share memory </li></ul></ul><ul><ul><li>Unusable in distributed systems </li></ul></ul><ul><li>Need higher-level primitives </li></ul><ul><ul><li>Based on semaphores or messages </li></ul></ul>
  5. 5. Solutions <ul><li>High-level share memory models </li></ul><ul><ul><li>Monitors </li></ul></ul><ul><ul><li>Protected Types </li></ul></ul><ul><li>Distributed schemes for interprocess communication/Synchronization </li></ul><ul><ul><li>Message-Based Communication </li></ul></ul><ul><ul><li>Procedure-Based Communication </li></ul></ul><ul><ul><li>Distributed Mutual Exclusion </li></ul></ul>
  6. 6. Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication Share Memory Methods
  7. 7. Monitors <ul><li>Higher level construct than semaphores . </li></ul><ul><li>A package of grouped procedures, variables and data, i.e., object oriented . </li></ul><ul><li>Processes call procedures within a monitor but cannot access internal data . </li></ul><ul><li>Can be built into programming languages , e,g., </li></ul><ul><ul><li>Mesa from Xerox was used to build a real operating system (Pilots). </li></ul></ul><ul><li>Synchronization enforced by the compiler . </li></ul><ul><li>Only one process allowed within a monitor at one time. </li></ul><ul><li>wait and signal operations on condition variables. </li></ul>
  8. 8. The Monitor Abstraction Shared among processes Processes cannot access them directly wait/signal primitives for processes communication or synchronization . Processes access the internal data only through these procedures. Procedure are mutually exclusive , i.e., only one process or thread may be executing a procedure within a given time. Internal Data Condition Variables Procedure 1 Procedure 2 Procedure 3
  9. 9. Example: Queue Handler Queue AddToQueue RemoveFromQueue
  10. 10. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>… add val to end of queue … </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>… remove value from queue, return it … </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>Using C-like Pseudo code. Since only one process may be executing a procedure within a given time, mutual exclusion is assured.
  11. 11. Process Synchronization <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>… add val to end of queue … </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>… remove value from queue, return it … </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>How about a process call RemoveFromQueue when the queue is empty?
  12. 12. Condition Variables <ul><li>Monitors need more facilities than just mutual exclusion. Need some way to wait . </li></ul><ul><li>For coordination, monitors provide: </li></ul><ul><li>c.wait </li></ul><ul><ul><li>Calling process is blocked and placed on waiting queue associated with condition variable c </li></ul></ul><ul><li>c.signal (Hoare) </li></ul><ul><li>c.notify (Mesa) </li></ul><ul><ul><li>Calling process wakes up first process on c queue </li></ul></ul>Question: How about the procedure that makes the c.signal ( c.notify ) call? sleep or keep running ?
  13. 13. Variations on Semantics <ul><li>Hoare semantics: awakened process gets monitor lock immediately. </li></ul><ul><ul><li>Process doing the signal gets “thrown out” temporarily. </li></ul></ul><ul><ul><li>Probably need to signal as the last thing in the monitor (Hansen). </li></ul></ul><ul><li>Mesa semantics: signaler keeps monitor lock. </li></ul><ul><ul><li>Awakened process waits for monitor lock with no special priority (a new process could get in before it). </li></ul></ul><ul><ul><li>This means that the event it was waiting for could have come and gone: must check again (use a loop ) and be prepared to wait again if someone else took it. </li></ul></ul><ul><ul><li>Signal and broadcast are therefore hints rather than guarantees. </li></ul></ul>wait/signal wait/notify
  14. 14. More on Condition Variables <ul><li>“ Condition variable” c is not a conventional variable </li></ul><ul><ul><li>c has no value </li></ul></ul><ul><ul><li>c is an arbitrary name chosen by programmer to designate an event , state , or condition </li></ul></ul><ul><ul><li>Each c has a waiting queue associated </li></ul></ul><ul><ul><li>A process may “block” itself on c -- it waits until another process issues a signal on c </li></ul></ul>
  15. 15. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>if ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>if ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>One must ensure that the queue is not full before adding the item. An item is available here. One must ensure that the queue is nonempty before remove an item. A free node is available here.
  16. 16. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>if ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>if ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>One must ensure that the queue is not full before adding the item. An item is available here. One must ensure that the queue is nonempty before remove an item. A free node is available here. An event denotes that data item is available in the queue. An event denotes that some more item can be added to the queue.
  17. 17. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>if ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>if ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>An item is available here. One must ensure that the queue is nonempty before remove an item. A free node is available here.
  18. 18. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>if ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>if ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>An item is available here. A free node is available here.
  19. 19. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>if ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>if ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>A free node is available here.
  20. 20. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>if ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>if ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>
  21. 21. Hoare Monitors <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>if ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>if ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>Queue is full p1 call AddtoQueue 1 p2 call RemoveFromQueue 3 2 p1 is blocked on freenodeAvail 5 P1 continues 4 P2 Signals freenodeAvail event 5’ P2 is blocked 6 P1 terminates 7 P2 continues
  22. 22. Example: Bounded Buffer Deposit Remove . . . . . . . . . 0 1 2 n  1 n  2
  23. 23. Example: Bounded Buffer Deposit Remove . . . . . . . . . 0 1 2 n  1 n  2 . . . nextin nextout count
  24. 24. Example: Bounded Buffer Deposit Remove count nextout nextin
  25. 25. Example: Bounded Buffer <ul><li>monitor BoundedBuffer { </li></ul><ul><ul><li>char buffer[n]; </li></ul></ul><ul><ul><li>int nextin=0, nextout=0, count=0; </li></ul></ul><ul><ul><li>condition notempty , notfull ; </li></ul></ul><ul><ul><li>deposit (char data) { </li></ul></ul><ul><ul><ul><li>if (count==n) notfull .wait; </li></ul></ul></ul><ul><ul><ul><li>buffer[nextin] = data; </li></ul></ul></ul><ul><ul><ul><li>nextin = (nextin+1) % n; </li></ul></ul></ul><ul><ul><ul><li>count = count+1; </li></ul></ul></ul><ul><ul><ul><li>notempty .signal; </li></ul></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>remove (char data) { </li></ul></ul><ul><ul><ul><li>if (count==0) notempty .wait; </li></ul></ul></ul><ul><ul><ul><li>data = buffer[nextout]; </li></ul></ul></ul><ul><ul><ul><li>nextout = (nextout+1) % n; </li></ul></ul></ul><ul><ul><ul><li>count = count - 1; </li></ul></ul></ul><ul><ul><ul><li>notfull .signal; </li></ul></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>}; </li></ul>
  26. 26. Priority Waits <ul><li>Hoare monitor signal resumes longest waiting process . </li></ul><ul><li>Not always what one wants, so Hoare introduced “ Priority Waits ” (aka “conditional” or “scheduled”): </li></ul><ul><li>c.wait( p ) </li></ul><ul><ul><li>p is an integer (priority) </li></ul></ul><ul><ul><li>Blocked processes are kept sorted by p </li></ul></ul><ul><li>c.signal </li></ul><ul><ul><li>Wakes up process with lowest p </li></ul></ul>
  27. 27. Example: Alarm Clock 0 1 3 2 4 5 . . . The current time ( now ) of the alarm clock is increased periodically ( tick ). Wakeup Queue The wakeup queue is used to hold processes to be waken up orderly according to their wakeup time ( alarm ) .
  28. 28. Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) Call at time 150
  29. 29. Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) p2: . . . AlarmClock.Wakeme(150); . . . p1(250) p2(350) Call at time 150 Call at time 200
  30. 30. Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) p2: . . . AlarmClock.Wakeme(150); . . . p1(250) p2(350) p3: . . . AlarmClock.Wakeme(30); . . . p3(240) Call at time 150 Call at time 200 Call at time 210
  31. 31. Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) p2: . . . AlarmClock.Wakeme(150); . . . p1(250) p2(350) p3: . . . AlarmClock.Wakeme(30); . . . p3(240) p4: . . . AlarmClock.Wakeme(10); . . . p4(240) Call at time 150 Call at time 200 Call at time 210 Call at time 230
  32. 32. Example: Alarm Clock <ul><li>monitor AlarmClock { </li></ul><ul><li>int now=0; </li></ul><ul><li>condition wakeup ; </li></ul><ul><ul><li>wakeme (int n) { </li></ul></ul><ul><ul><li>int alarm; </li></ul></ul><ul><ul><li>alarm = now + n; </li></ul></ul><ul><ul><li>while (now<alarm) wakeup .wait(alarm); </li></ul></ul><ul><ul><li>wakeup .signal; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>tick () { </li></ul></ul><ul><ul><li>/*invoked automatically by hardware*/ </li></ul></ul><ul><ul><li>now = now + 1; </li></ul></ul><ul><ul><li>wakeup .signal; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>} </li></ul>
  33. 33. Example: Alarm Clock p1: . . . AlarmClock.Wakeme(100); . . . Wakeup Queue p1(250) p2: . . . AlarmClock.Wakeme(150); . . . p1(250) p2(350) p3: . . . AlarmClock.Wakeme(30); . . . p3(240) p4: . . . AlarmClock.Wakeme(10); . . . p4(240) Call at time 150 Call at time 200 Call at time 210 Call at time 230
  34. 34. Mesa and Java Monitors <ul><li>notify is a variant of signal </li></ul><ul><li>After c.notify : </li></ul><ul><ul><li>Calling process continues </li></ul></ul><ul><ul><li>Woken-up process continues when caller exits </li></ul></ul><ul><li>Problems </li></ul><ul><ul><li>Caller may wake up multiple processes, e.g., </li></ul></ul><ul><ul><li>P i , P j , P k , … </li></ul></ul><ul><ul><li>P i could change condition on which P j was blocked </li></ul></ul>
  35. 35. Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . . . . . B1=FASLE; . . . . . . . .
  36. 36. Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . . . . . B1=FASLE; return; P3: . . . . . . . . B1=B2=TRUE; c1.notify; c2.notify; . . . . . . . . return; B1=FALSE
  37. 37. Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . . . . . B1=FASLE; return; P3: . . . . . . . . B1=B2=TRUE; c1.notify; c2.notify; . . . . . . . . return; B1=FALSE What action should P1 take? Continue or wait again?
  38. 38. Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . . . . . B1=FASLE; return; P3: . . . . . . . . B1=B2=TRUE; c1.notify; c2.notify; . . . . . . . . return; B1=FALSE What action should P1 take? Continue or wait again? 
  39. 39. Solution P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . . . . . B1=FASLE; return; P3: . . . . . . . . B1=B2=TRUE; c1.notify; c2.notify; . . . . . . . . return; B1=FALSE What action should P1 take? Continue or wait again?    Replace if to while . while while
  40. 40. Example: Queue Handler Queue AddToQueue RemoveFromQueue
  41. 41. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>if ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>if ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>Hoare monitors use ` if ’.
  42. 42. Example: Queue Handler <ul><li>monitor QueueHandler { </li></ul><ul><ul><li>struct Queue queue ; </li></ul></ul><ul><ul><li>condition itemAvail , freenodeAvail ; </li></ul></ul><ul><ul><li>void AddToQueue ( int val ) { </li></ul></ul><ul><ul><ul><li>while ( queue is full ) { </li></ul></ul></ul><ul><ul><ul><li>freenodeAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . add val to the end of the queue . . . </li></ul></ul><ul><ul><li>itemAvail.signal ; </li></ul></ul><ul><ul><li>} /* AddToQueue */ </li></ul></ul><ul><ul><li>int RemoveFromQueue () { </li></ul></ul><ul><ul><ul><li>while ( queue is empty ) { </li></ul></ul></ul><ul><ul><ul><li>itemAvail .wait; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>. . . remove value from queue . . . </li></ul></ul><ul><ul><li>freenodeAvail .signal; </li></ul></ul><ul><ul><li>return value; </li></ul></ul><ul><ul><li>} /* RemoveFromQueue */ </li></ul></ul><ul><li>}; </li></ul>Mesa monitors use ` while ’.
  43. 43. Protected Types <ul><li>Special case of monitor where: </li></ul><ul><ul><li>c.wait is the first operation of a procedure </li></ul></ul><ul><ul><li>c.signal is the last operation </li></ul></ul><ul><li>Typical in producer/consumer situations </li></ul><ul><li>wait/signal combined into a when clause </li></ul><ul><ul><li>when c forms a “ barrier ” or “ guarded ” </li></ul></ul><ul><ul><li>Procedure continues only when c is true </li></ul></ul>Defined in the Ada95 language (ADA 1995).
  44. 44. Example: Bounded Buffer <ul><li>Protected body BoundedBuffer { </li></ul><ul><li>char buffer[n]; </li></ul><ul><li>int nextin=0, nextout=0, count=0; </li></ul><ul><li>entry deposit (char c) </li></ul><ul><ul><li>when (count < n) /* guard */ { </li></ul></ul><ul><ul><li>buffer[nextin] = c; </li></ul></ul><ul><ul><li>nextin = (nextin + 1) % n; </li></ul></ul><ul><ul><li>count = count + 1; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>entry remove (char c) </li></ul><ul><ul><li>when (count > 0) /* guard */ { </li></ul></ul><ul><ul><li>c = buffer[nextout]; </li></ul></ul><ul><ul><li>nextout = (nextout + 1) % n; </li></ul></ul><ul><ul><li>count = count - 1; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>} </li></ul>
  45. 45. Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication Distributed Synchronization and Communication
  46. 46. Distributed Synchronization <ul><li>Semaphore-based primitive </li></ul><ul><ul><li>Requires Shared Memory </li></ul></ul><ul><li>For Distributed Memory: </li></ul><ul><ul><li>send( p , m ) </li></ul></ul><ul><ul><li>Send message m to process p </li></ul></ul><ul><ul><li>receive( q , m ) </li></ul></ul><ul><ul><li>Receive message from process q in variable m </li></ul></ul><ul><li>Semantics of send and receive vary very substantially in different systems. </li></ul>
  47. 47. Questions of Send/Receive <ul><li>Does sender wait for message to be accepted? </li></ul><ul><li>Does receiver wait if there is no message? </li></ul><ul><li>Does sender name exactly one receiver? </li></ul><ul><li>Does receiver name exactly one sender? </li></ul>
  48. 48. Types of Send/Receive broadcast message m broadcast message m wait until accepted implicit naming send message m to receiver r send message m to receiver r wait until accepted explicit naming nonblocking/asynchronous blocking/synchronous send if there is a message from any sender, then receive it; else proceed. wait message from any sender implicit naming if there is a message from sender s , then receive it; else proceed. wait message from sender s explicit naming nonblocking/asynchronous blocking/synchronous receive
  49. 49. Types of Send/Receive broadcast message m broadcast message m wait until accepted implicit naming send message m to receiver r send message m to receiver r wait until accepted explicit naming nonblocking/asynchronous blocking/synchronous send if there is a message from any sender, then receive it; else proceed. wait message from any sender implicit naming if there is a message from sender s , then receive it; else proceed. wait message from sender s explicit naming nonblocking/asynchronous blocking/synchronous receive if there is a message from any sender, then receive it; else proceed. wait message from any sender implicit naming if there is a message from sender s , then receive it; else proceed. wait message from sender s explicit naming nonblocking/asynchronous blocking/synchronous receive
  50. 50. Types of Send/Receive Little practical used Little practical used Little practical used  no use, e.g., Some debugging software may like it. broadcast message m broadcast message m wait until accepted implicit naming send message m to receiver r send message m to receiver r wait until accepted explicit naming nonblocking/asynchronous blocking/synchronous send if there is a message from any sender, then receive it; else proceed. wait message from any sender implicit naming if there is a message from sender s , then receive it; else proceed. wait message from sender s explicit naming nonblocking/asynchronous blocking/synchronous receive
  51. 51. Process Coordination Little practical used Little practical used Solving a variety of process coordination problems. broadcast message m broadcast message m wait until accepted implicit naming send message m to receiver r send message m to receiver r wait until accepted explicit naming nonblocking/asynchronous blocking/synchronous send if there is a message from any sender, then receive it; else proceed. wait message from any sender implicit naming if there is a message from sender s , then receive it; else proceed. wait message from sender s explicit naming nonblocking/asynchronous blocking/synchronous receive
  52. 52. Example:Printer Sever Little practical used Little practical used broadcast message m broadcast message m wait until accepted implicit naming send message m to receiver r send message m to receiver r wait until accepted explicit naming nonblocking/asynchronous blocking/synchronous send if there is a message from any sender, then receive it; else proceed. wait message from any sender implicit naming if there is a message from sender s , then receive it; else proceed. wait message from sender s explicit naming nonblocking/asynchronous blocking/synchronous receive
  53. 53. Implementation for Asynchronous Operations Little practical used Little practical used built-in buffers are required to hold messages broadcast message m broadcast message m wait until accepted implicit naming send message m to receiver r send message m to receiver r wait until accepted explicit naming nonblocking/asynchronous blocking/synchronous send if there is a message from any sender, then receive it; else proceed. wait message from any sender implicit naming if there is a message from sender s , then receive it; else proceed. wait message from sender s explicit naming nonblocking/asynchronous blocking/synchronous receive
  54. 54. Channels, Ports, and Mailboxes <ul><li>Allow indirect communication: </li></ul><ul><ul><li>Senders/Receivers name channel instead of processes </li></ul></ul><ul><ul><li>Senders/Receivers determined at runtime </li></ul></ul><ul><ul><ul><li>Sender does not need to know who receives the message </li></ul></ul></ul><ul><ul><ul><li>Receiver does not need to know who sent the message </li></ul></ul></ul>
  55. 55. Named Message Channels Named Pipe (Win32) P1: . . . . . . . . send(ch1, msg1); . . . . . . . . P2: . . . . . . . . send(ch2, msg2); . . . . . . . . P3: . . . . . . . . receive(ch1, x); . . . . . . . . receive(ch2, y); . . . . . . . . ch1 ch2
  56. 56. CSP/Occam <ul><li>Using Named channel , say, ch1 to connect processes, say, p1 and p2 </li></ul><ul><ul><li>p1 sends to p2 using: send( ch1 , ’a’ ) </li></ul></ul><ul><ul><li>p2 receives from p1 using: receive( ch1 , x ) </li></ul></ul><ul><ul><li>Guarded commands: </li></ul></ul><ul><ul><li>when ( c ) s </li></ul></ul><ul><ul><ul><li>Set of statements s executed only when c is true </li></ul></ul></ul><ul><ul><ul><li>Allow processes to receive messages selectively based on arbitrary conditions </li></ul></ul></ul>CSP: Communicating Sequential Processes Occam: a Language
  57. 57. Bounded buffer with CSP <ul><li>Communicating Sequential Processes: </li></ul><ul><ul><li>Buffer B </li></ul></ul><ul><ul><li>Producer P </li></ul></ul><ul><ul><li>Consumer C </li></ul></ul><ul><li>Problems: </li></ul><ul><ul><li>When Buffer full : B can only send to C </li></ul></ul><ul><ul><li>When Buffer empty : B can only receive from P </li></ul></ul><ul><ul><li>When Buffer partially filled : B must know whether C or P is ready to act </li></ul></ul><ul><li>Solution: </li></ul><ul><ul><li>C sends request to B first; B then sends data </li></ul></ul><ul><ul><li>Inputs from P and C are guarded with when </li></ul></ul>B P C
  58. 58. Bounded buffer with CSP Buffer Producer Consumer deposit request remove
  59. 59. Bounded buffer with CSP Buffer Producer Consumer deposit request remove send(deposit, data) send(request) receive(remove,data) receive(request) send(remove,data) receive(deposit, data)
  60. 60. Bounded buffer with CSP Buffer Producer Consumer deposit request remove receive(request) send(remove,data) receive(deposit, data) The Bounded Buffer uses the following three primitives for synchronization.
  61. 61. Bounded buffer with CSP <ul><li>process BoundedBuffer { </li></ul><ul><li>char buf[n]; </li></ul><ul><li>int nextin=0, nextout=0, count=0; </li></ul><ul><li>while (1) { </li></ul><ul><li>when ((count<n) && receive(deposit, buf[nextin])){ </li></ul><ul><ul><ul><li>nextin = (nextin + 1) % n; </li></ul></ul></ul><ul><ul><ul><li>count = count + 1; </li></ul></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>or </li></ul></ul><ul><ul><li>when ((fullCount>0) && receive(reqest)){ </li></ul></ul><ul><ul><li> send(remove, buf[nextout]); </li></ul></ul><ul><ul><li> nextout = (nextout + 1) % n; </li></ul></ul><ul><ul><li> count = count - 1; </li></ul></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>Put data into buffer if buffer is not full and producer’s data is available. Pass data to the consumer if it has requested one.
  62. 62. Bounded buffer with CSP <ul><li>process BoundedBuffer { </li></ul><ul><li>char buf[n]; </li></ul><ul><li>int nextin=0, nextout=0, count=0; </li></ul><ul><li>while (1) { </li></ul><ul><li>when ((count<n) && receive ( deposit , buf[nextin])){ </li></ul><ul><ul><ul><li>nextin = (nextin + 1) % n; </li></ul></ul></ul><ul><ul><ul><li>count = count + 1; </li></ul></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>or </li></ul></ul><ul><ul><li>when ((fullCount>0) && receive(reqest)){ </li></ul></ul><ul><ul><li> send(remove, buf[nextout]); </li></ul></ul><ul><ul><li> nextout = (nextout + 1) % n; </li></ul></ul><ul><ul><li> count = count - 1; </li></ul></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>Pass data to the consumer if it has requested one.
  63. 63. Bounded buffer with CSP <ul><li>process BoundedBuffer { </li></ul><ul><li>char buf[n]; </li></ul><ul><li>int nextin=0, nextout=0, count=0; </li></ul><ul><li>while (1) { </li></ul><ul><li>when ((count<n) && receive ( deposit , buf[nextin])){ </li></ul><ul><ul><ul><li>nextin = (nextin + 1) % n; </li></ul></ul></ul><ul><ul><ul><li>count = count + 1; </li></ul></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>or </li></ul></ul><ul><ul><li>when ((count>0) && receive ( request )){ </li></ul></ul><ul><ul><li> send ( remove , buf[nextout]); </li></ul></ul><ul><ul><li> nextout = (nextout + 1) % n; </li></ul></ul><ul><ul><li> count = count - 1; </li></ul></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  64. 64. More on Named Channels <ul><li>Each named channel serves for a particular purpose . </li></ul><ul><li>Processes are connected through named channels directly . </li></ul>Buffer Producer Consumer deposit request remove
  65. 65. Ports and Mailboxes Port Mailboxes
  66. 66. Ports and Mailboxes <ul><li>Processes are connected through intermediary . </li></ul><ul><ul><li>Allowing a receiver to receive from multiple senders (nondeterministically). </li></ul></ul><ul><ul><li>Sending can be nonblocking . </li></ul></ul><ul><li>The intermediary usually is a queue . </li></ul><ul><li>The queue is called mailbox or port , depending on number of receivers: </li></ul><ul><ul><li>mailbox can have multiple senders and receivers </li></ul></ul><ul><ul><li>port can have only one receiver </li></ul></ul>
  67. 67. Ports and Mailboxes
  68. 68. Procedure-Based Communication <ul><li>Send/Receive are too low level (like P/V ) </li></ul><ul><li>Typical interaction among processes: </li></ul><ul><ul><li>Send Request & (then) Receive Result. </li></ul></ul><ul><ul><li>Make this into a single higher-level primitive. </li></ul></ul><ul><li>Use RPC (Remote Procedure Call) or Rendezvous </li></ul><ul><ul><li>Caller invokes procedure on remote machine. </li></ul></ul><ul><ul><li>Remote machine performs operation and returns result. </li></ul></ul><ul><ul><li>Similar to regular procedure call , but parameters cannot contain pointers because caller and server do not share any memory. </li></ul></ul>
  69. 69. Procedure-Based Communication <ul><li>Send/Receive are too low level (like P/V ) </li></ul><ul><li>Typical interaction among processes: </li></ul><ul><ul><li>Send Request & (then) Receive Result. </li></ul></ul><ul><ul><li>Make this into a single higher-level primitive. </li></ul></ul><ul><li>Use RPC (Remote Procedure Call) or Rendezvous </li></ul><ul><ul><li>Caller invokes procedure on remote machine. </li></ul></ul><ul><ul><li>Remote machine performs operation and returns result. </li></ul></ul><ul><ul><li>Similar to regular procedure call , but parameters cannot contain pointers because caller and server do not share any memory. </li></ul></ul>In fact, it ` can ’ by doing marshalling on parameters.
  70. 70. RPC <ul><li>Caller issues: res = f( params ) </li></ul><ul><li>This is translated into: </li></ul>res = f( params ) // caller // client process ... send(RP, f , params ); receive(RP,res); ... // callee // server process process RP_server { while (1) { receive(C, f , params ); res= f( params ) ; send(C,res); } }
  71. 71. Rendezvous <ul><li>With RPC : </li></ul><ul><ul><li>Called process p is part of a dedicated server </li></ul></ul><ul><ul><li>Setup is asymmetrical  Client-sever relation </li></ul></ul><ul><li>With Rendezvous : </li></ul><ul><ul><li>p is part of an arbitrary process </li></ul></ul><ul><ul><li>p maintains state between calls </li></ul></ul><ul><ul><li>p may accept/delay/reject call </li></ul></ul><ul><ul><li>Setup is symmetrical : Any process may be a client or a server </li></ul></ul>“ Rendezvous ” is French for “ meeting .” Pronunciation  “ RON-day-voo .”
  72. 72. Rendezvous Caller Server q . f ( param ) accept f ( param ) S Similar syntax/semantics to RPC Name of the remote process (sever) Procedure name Procedure parameter Procedure body Keyword
  73. 73. Semantics of a Rendezvous <ul><li>Caller or Server waits for the other . </li></ul><ul><li>Then, they execute in parallel . </li></ul>
  74. 74. Semantics of a Rendezvous p q Rendezvous p q Rendezvous q . f () accept f () S q . f () accept f () S
  75. 75. Rendezvous: Selective Accept <ul><ul><ul><li>select { </li></ul></ul></ul><ul><ul><ul><li>[when B1:] accept E1 (…) S1; </li></ul></ul></ul><ul><ul><ul><li>or </li></ul></ul></ul><ul><ul><ul><li>[when B2:] accept E2 (…) S2; </li></ul></ul></ul><ul><ul><ul><li>or </li></ul></ul></ul><ul><ul><ul><li>. </li></ul></ul></ul><ul><ul><ul><li>. </li></ul></ul></ul><ul><ul><ul><li>. </li></ul></ul></ul><ul><ul><ul><li>or </li></ul></ul></ul><ul><ul><ul><li>[when Bn:] accept En (…) Sn; </li></ul></ul></ul><ul><ul><ul><li>[else R] </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><li>Ada provides a select statement that permits multiple accepts (guarded or not) to be active simultaneous. </li></ul><ul><li>Only one could be selected nondeterministically upon Rendezvous. </li></ul>
  76. 76. Rendezvous: Selective Accept [. . .] : optional <ul><ul><ul><li>select { </li></ul></ul></ul><ul><ul><ul><li>[when B1:] accept E1 (…) S1; </li></ul></ul></ul><ul><ul><ul><li>or </li></ul></ul></ul><ul><ul><ul><li>[when B2:] accept E2 (…) S2; </li></ul></ul></ul><ul><ul><ul><li>or </li></ul></ul></ul><ul><ul><ul><li>. </li></ul></ul></ul><ul><ul><ul><li>. </li></ul></ul></ul><ul><ul><ul><li>. </li></ul></ul></ul><ul><ul><ul><li>or </li></ul></ul></ul><ul><ul><ul><li>[when Bn:] accept En (…) Sn; </li></ul></ul></ul><ul><ul><ul><li>[else R] </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  77. 77. Example: Bounded Buffer <ul><ul><ul><li>process BoundedBuffer { </li></ul></ul></ul><ul><ul><ul><li>char buffer[n]; </li></ul></ul></ul><ul><ul><ul><li>int nextin=0, nextout=0, count=0; </li></ul></ul></ul><ul><ul><ul><ul><ul><li>while(1) { </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>select { </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>when (fullCount < n): </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>accept deposit (char c) { </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>buffer[nextin] = c; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>nextin = (nextin + 1) % n; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>count = count + 1; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>or </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>when (count > 0): </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>accept remove (char c) { </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>c = buffer[nextout]; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>nextout = (nextout + 1) % n; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>count = count - 1; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><li>To provide the following services forever: </li></ul><ul><li>deposit </li></ul><ul><li>remove </li></ul>
  78. 78. Example: Bounded Buffer <ul><ul><ul><li>process BoundedBuffer { </li></ul></ul></ul><ul><ul><ul><li>char buffer[n]; </li></ul></ul></ul><ul><ul><ul><li>int nextin=0, nextout=0, count=0; </li></ul></ul></ul><ul><ul><ul><ul><ul><li>while(1) { </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>select { </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>when (count < n): </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>accept deposit (char c) { </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>buffer[nextin] = c; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>nextin = (nextin + 1) % n; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>count = count + 1; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>or </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>when (count > 0): </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>accept remove (char c) { </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>c = buffer[nextout]; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>nextout = (nextout + 1) % n; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>count = count - 1; </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul></ul><ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  79. 79. Example: Bounded Buffer BoundedBuffer .deposit(data) BoundedBuffer .remove(data)
  80. 80. Distributed Mutual Exclusion <ul><li>CS problem in a Distributed Environment </li></ul><ul><ul><li>No shared memory , No shared clock , </li></ul></ul><ul><ul><li>Delays in message transmission . </li></ul></ul><ul><li>Central Controller Solution </li></ul><ul><ul><li>Requesting process sends request to controller </li></ul></ul><ul><ul><li>Controller grant it to one processes at a time </li></ul></ul><ul><ul><li>Problems: </li></ul></ul><ul><ul><ul><li>Single point of failure , </li></ul></ul></ul><ul><ul><ul><li>Performance bottleneck </li></ul></ul></ul><ul><li>Fully Distributed Solution: </li></ul><ul><ul><li>Processes negotiate access among themselves </li></ul></ul><ul><ul><li>Very complex </li></ul></ul>
  81. 81. Distributed Mutual Exclusion with Token Ring A practical and elegant compromise version of fully distributed approach.
  82. 82. Distributed Mutual Exclusion with Token Ring Controler[2]: P[2]: CS2; Program2; Controler[3]: P[3]: CS3; Program3; Controler[1]: P[1]: CS1; Program1; token token RequestCS ReleaseCS RequestCS ReleaseCS RequestCS ReleaseCS
  83. 83. Distributed Mutual Exclusion with Token Ring Controler[2]: P[2]: CS2; Program2; Controler[3]: P[3]: CS3; Program3; Controler[1]: P[1]: CS1; Program1; process controller[i] { while(1) { accept Token; select { accept Request_CS () {busy=1;} else null; } if (busy) accept Release_CS () {busy=0;} controller[(i+1) % n].Token; } } process p[i ] { while(1) { controller[i]. Request_CS (); CSi; controller[i]. Release_CS (); programi; } } <ul><li>Do four possible jobs: </li></ul><ul><li>Receive token </li></ul><ul><li>Transmit token </li></ul><ul><li>Lock token ( RequestCS ) </li></ul><ul><li>Unlock token ( ReleaseCS ) </li></ul>token token RequestCS ReleaseCS RequestCS ReleaseCS RequestCS ReleaseCS
  84. 84. Distributed Mutual Exclusion with Token Ring Controler[2]: P[2]: CS2; Program2; Controler[3]: P[3]: CS3; Program3; Controler[1]: P[1]: CS1; Program1; process controller[i] { while(1) { accept Token; select { accept Request_CS () {busy=1;} else null; } if (busy) accept Release_CS () {busy=0;} controller[(i+1) % n].Token; } } process p[i ] { while(1) { controller[i]. Request_CS (); CSi; controller[i]. Release_CS (); programi; } } token token RequestCS ReleaseCS RequestCS ReleaseCS RequestCS ReleaseCS
  85. 85. Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication Other Classical Problems
  86. 86. Readers/Writers Problem Database
  87. 87. Readers/Writers Problem Database Writers can work only when no reader activated. One Writer can work at a time.
  88. 88. Readers/Writers Problem Database Readers can work only when no writer activated. Allows infinite number of readers.
  89. 89. Readers/Writers Problem <ul><li>Extension of basic CS problem </li></ul><ul><ul><li>(Courtois, Heymans, and Parnas, 1971) </li></ul></ul><ul><li>Two types of processes entering a CS: </li></ul><ul><ul><li>Only one Writer (W) may be inside CS, (exclusive) or </li></ul></ul><ul><ul><li>Many Readers (Rs) may be inside CS </li></ul></ul><ul><li>Prevent starvation of either process type: </li></ul><ul><ul><li>If Rs are in CS, a new R must not enter if W is waiting </li></ul></ul><ul><ul><li>If W is in CS, once it leaves, all Rs waiting should enter (even if they arrived after new Ws ) </li></ul></ul>
  90. 90. Solution Using Monitor monitor Readers_Writers { int readCount=0, writing=0; condition OK_R, OK_W; start_read() { if (writing || !empty(OK_W)) OK_R.wait; readCount = readCount + 1; OK_R.signal; } end_read() { readCount = readCount - 1; if (readCount == 0) OK_W.signal; } start_write() { if ((readCount != 0)||writing) OK_W.wait; writing = 1; } end_write() { writing = 0; if (!empty(OK_R)) OK_R.signal; else OK_W.signal; } } Called by a reader that wishes to read. Called by a reader that has finished reading. Called by a writer that wishes to write. Called by a writer that has finished writing.
  91. 91. Solution Using Monitor monitor Readers_Writers { int readCount=0, writing=0; condition OK_R, OK_W; start_read() { if (writing || ! empty (OK_W)) OK_R.wait; readCount = readCount + 1; OK_R.signal; } end_read() { readCount = readCount - 1; if (readCount == 0) OK_W.signal; } start_write() { if ((readCount != 0)||writing) OK_W.wait; writing = 1; } end_write() { writing = 0; if (! empty (OK_R)) OK_R.signal; else OK_W.signal; } } Additional Primitive: empty ( c ) Return true if the associated queue of c is empty.
  92. 92. Dining Philosophers
  93. 93. Dining Philosophers <ul><li>Five philosophers sit around a circular table. </li></ul><ul><li>In the centre of the table is a large plate of spaghetti . </li></ul><ul><li>Each philosopher spends his life alternatively thinking and eating . </li></ul><ul><li>A philosopher needs two forks to eat. </li></ul><ul><li>Requirements </li></ul><ul><ul><li>Prevent deadlock </li></ul></ul><ul><ul><li>Guarantee fairness : no philosopher must starve </li></ul></ul><ul><ul><li>Guarantee concurrency : non-neighbors may eat at the same time </li></ul></ul>
  94. 94. Dining Philosophers p 1 p 2 p 3 p 4 p 5 f 1 f 2 f 3 f 4 f 5 p(i) { while (1) { think(i); grab_forks (i); eat(i); return_forks (i); } } grab_forks (i): P(f[i]); P(f[(i+1)%5]); <ul><ul><li>return_forks (i): V(f[i]); V(f[(i+1)%5]); </li></ul></ul>Easily lead to deadlock .
  95. 95. Solutions to deadlock <ul><li>Use a counter : </li></ul><ul><ul><li>At most n  1 philosophers may attempt to grab forks. </li></ul></ul><ul><li>One philosopher requests forks in reverse order, e.g., grab_forks (1): P (f[2]); P (f[1]); </li></ul><ul><li>Divide philosophers into two groups : </li></ul><ul><ul><li>Odd grab Left fork first , </li></ul></ul><ul><ul><li>Even grab Right fork first </li></ul></ul>
  96. 96. Logical Clocks <ul><li>Many applications need to time-stamp events </li></ul><ul><ul><li>for debugging , recovery, distributed mutual exclusion, ordering of broadcast messages, transactions , etc. </li></ul></ul><ul><li>Time-stamp allows us to determine the causality of events. </li></ul><ul><ul><li>C(e1)<C(e2) means e 1 happened before e2 . </li></ul></ul><ul><li>Global clock is unavailable for distributed systems. </li></ul><ul><li>Physical clocks in distributed systems are skewed . </li></ul>
  97. 97. The Problem of Clock Skewness File User (U) File Server (FS) e 1 e 2 e 3 e 4 C U C FS send send receive receive delta 1 delta 2 True causality of events: The log of events: 10 15 5 20 Impossible sequence!
  98. 98. Logical Clocks e i e s e k e r send receive p 1 p 2 e j
  99. 99. Logical Clocks in Action u v x y 4 5 13 15 6 14
  100. 100. The Elevator Algorithm <ul><li>The simple algorithm by which a single elevator can decide where to stop is: </li></ul><ul><ul><li>Continue traveling in the same direction while there are remaining requests in that same direction . </li></ul></ul><ul><ul><li>If there are no further requests then change direction . </li></ul></ul><ul><li>Scheduling hard disk requests. </li></ul>
  101. 101. The Elevator Algorithm
  102. 102. The Elevator Algorithm <ul><li>Pressing button at floor i or button i inside elevator invokes: request(i) </li></ul><ul><li>Door closing , invokes: release() </li></ul><ul><li>Scheduler policy: </li></ul><ul><ul><li>direction = up : </li></ul></ul><ul><ul><li>it services all requests at or above current position; then it reverses direction </li></ul></ul><ul><ul><li>direction = down : </li></ul></ul><ul><ul><li>it services all requests at or below current position; then it reverses direction </li></ul></ul>request ( i ) request ( i ) direction = up driection = down
  103. 103. The Elevator Algorithm Using Priority Waits monitor elevator { int dir=1, up=1, down=-1, pos=1, busy=0; condition upsweep , downsweep ; request (int dest) { /*Called when button pushed*/ if (busy) { if ((pos<dest) || ((pos==dest) && (dir==up))) upsweep .wait(dest); else downsweep .wait(-dest); } busy = 1; pos = dest; } release () { /*Called when door closes*/ . . . . . . . . . . . . . . . } } Put the request into the proper priority queue and wait .
  104. 104. The Elevator Algorithm Using Priority Waits monitor elevator { int dir=1, up=1, down=-1, pos=1, busy=0; condition upsweep , downsweep ; request (int dest) { /*Called when button pushed*/ if (busy) { if ((pos<dest) || ((pos==dest) && (dir==up))) upsweep .wait(dest); else downsweep .wait(-dest); } busy = 1; pos = dest; } release () { /*Called when door closes*/ . . . . . . . . . . . . . . . } }
  105. 105. The Elevator Algorithm Using Priority Waits monitor elevator { int dir=1, up=1, down=-1, pos=1, busy=0; condition upsweep, downsweep; . . . . . . . . . . . . . . . release () { /*Called when door closes*/ busy = 0; if (dir==up) { if (!empty( upsweep )) upsweep .signal; else { dir = down; downsweep .signal; } } else { /*direction==down*/ if (!empty(downsweep)) downsweep .signal; else { dir = up; upsweep .signal; } } } }

×