SlideShare a Scribd company logo
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication 主講人:虞台文
Content Motivation Shared Memory Methods  Monitors  Protected Types Distributed Synchronization/Communication Message-Based Communication  Procedure-Based Communication  Distributed Mutual Exclusion Other Classical Problems The Readers/Writers Problem The Dining Philosophers Problem  The Elevator Algorithm Event Ordering with Logical Clocks
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication Motivation
Motivation Semaphores and Events Powerful but  low-level  abstractions Such programs are  difficult  to design, debug, and maintain Programming with them is  highly error prone , e.g., deadlock Insecure  for share memory Unusable  in  distributed  systems Need higher-level primitives  Based on semaphores or messages
Solutions High-level  share memory  models Monitors  Protected Types Distributed  schemes for interprocess communication/Synchronization Message-Based Communication  Procedure-Based Communication  Distributed Mutual Exclusion
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication Share Memory Methods
Monitors Higher level  construct than  semaphores . A package of grouped procedures, variables and data, i.e.,  object oriented . Processes  call  procedures within a monitor but  cannot  access  internal data . Can be built into  programming languages , e,g., Mesa  from  Xerox  was used to build a real operating system (Pilots). Synchronization enforced by the  compiler . Only one  process allowed within a monitor at one time. wait  and  signal  operations on condition variables.
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
Example: Queue Handler Queue AddToQueue RemoveFromQueue
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; void  AddToQueue ( int val ) { …  add val to end of queue … } /* AddToQueue */ int  RemoveFromQueue () { …  remove value from queue, return it … } /* RemoveFromQueue */ }; Using C-like Pseudo code. Since only one process may be executing a procedure within a given time,  mutual exclusion  is assured.
Process Synchronization monitor  QueueHandler { struct Queue  queue ; void  AddToQueue ( int val ) { …  add val to end of queue … } /* AddToQueue */ int  RemoveFromQueue () { …  remove value from queue, return it … } /* RemoveFromQueue */ }; How about a process call  RemoveFromQueue  when the  queue  is empty?
Condition Variables Monitors need more facilities than just mutual exclusion. Need some way to  wait . For coordination, monitors provide: c.wait Calling process is  blocked  and placed on waiting queue associated with condition variable  c c.signal  (Hoare) c.notify  (Mesa) Calling process  wakes up  first process on  c  queue Question: How about the procedure that makes the  c.signal  ( c.notify )  call? sleep  or keep  running ?
Variations on  Semantics Hoare semantics:  awakened process gets monitor lock immediately. Process doing the signal  gets  “thrown out”  temporarily. Probably need to signal as the last thing in the monitor (Hansen). Mesa semantics:  signaler keeps monitor lock. Awakened process waits for monitor lock  with no special priority (a new process could get in before it). 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. Signal and broadcast are therefore  hints  rather than guarantees. wait/signal wait/notify
More on Condition Variables “ Condition variable”  c  is  not  a conventional variable c  has  no  value c  is an arbitrary name chosen by programmer to designate an  event ,  state , or  condition Each  c  has a  waiting queue  associated A process may “block” itself on  c  -- it waits until another process issues a signal on  c
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { if ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { if ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ }; 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.
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { if ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { if ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ }; 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.
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { if ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { if ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ }; An item is available here. One must ensure that the queue is  nonempty  before remove an item. A free node is available here.
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { if ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { if ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ }; An item is available here. A free node is available here.
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { if ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { if ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ }; A free node is available here.
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { if ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { if ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ };
Hoare Monitors monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { if ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { if ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ }; 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
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 monitor  BoundedBuffer  {  char buffer[n];  int nextin=0, nextout=0, count=0;  condition  notempty ,  notfull ; deposit (char data) {  if (count==n)  notfull .wait;  buffer[nextin] = data;  nextin = (nextin+1) % n;  count = count+1;  notempty .signal;  }  remove (char data) {  if (count==0)  notempty .wait;  data = buffer[nextout];  nextout = (nextout+1) % n;  count = count - 1;  notfull .signal;  }  };
Priority Waits Hoare monitor signal  resumes longest waiting process . Not always what one wants, so Hoare introduced “ Priority Waits ” (aka “conditional” or “scheduled”): c.wait( p ) p  is an integer (priority) Blocked processes are kept sorted by  p   c.signal Wakes up process with lowest  p
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 ) .
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); . . . p1(250) p2(350) Call at time 150 Call at time 200
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
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
Example: Alarm Clock monitor  AlarmClock  {  int now=0;  condition  wakeup ;  wakeme (int n) {  int alarm;  alarm = now + n;  while (now<alarm)  wakeup .wait(alarm);  wakeup .signal;  } tick () { /*invoked automatically by hardware*/ now = now + 1;  wakeup .signal;  } }
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
Mesa and Java Monitors notify   is a variant of  signal After  c.notify : Calling process continues Woken-up process continues when caller exits Problems Caller may wake up multiple processes, e.g., P i ,  P j ,  P k , … P i  could change condition on which  P j  was blocked
Mesa and Java Monitors P1: . . . . . . . . if(!B1) c1.wait; . . . . . . . . P2: . . . . . . . . if(!B2) c2.wait; . . . . . . . . B1=FASLE; . . . . . . . .
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
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?
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? 
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
Example: Queue Handler Queue AddToQueue RemoveFromQueue
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { if ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { if ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ }; Hoare monitors use ` if ’.
Example: Queue Handler monitor  QueueHandler { struct Queue  queue ; condition  itemAvail ,  freenodeAvail ; void  AddToQueue ( int val ) { while ( queue is full ) { freenodeAvail .wait; } . . . add val to the end of the queue . . . itemAvail.signal ; } /* AddToQueue */ int  RemoveFromQueue () { while ( queue is empty ) { itemAvail .wait; } . . . remove value from queue . . . freenodeAvail .signal; return value; } /* RemoveFromQueue */ }; Mesa monitors use ` while ’.
Protected Types Special case of monitor where: c.wait  is the  first  operation of a procedure c.signal  is the  last  operation Typical in  producer/consumer  situations wait/signal  combined into a  when  clause when c  forms a “ barrier ” or “ guarded ” Procedure continues only  when c  is true Defined in the  Ada95  language (ADA 1995).
Example: Bounded Buffer Protected  body BoundedBuffer { char buffer[n]; int nextin=0, nextout=0, count=0; entry  deposit (char c)  when  (count < n)  /* guard */  {  buffer[nextin] = c;  nextin = (nextin + 1) % n;  count = count + 1;  }  entry   remove (char c)  when  (count > 0)  /* guard */  {  c = buffer[nextout];  nextout = (nextout + 1) % n;  count = count - 1;  } }
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication Distributed Synchronization and Communication
Distributed Synchronization Semaphore-based primitive Requires  Shared Memory For Distributed Memory: send( p , m ) Send message  m  to process  p receive( q , m ) Receive message from process  q  in variable  m Semantics  of  send  and  receive  vary very substantially in different systems.
Questions of  Send/Receive Does  sender   wait  for message to be accepted? Does  receiver   wait  if there is no message? Does  sender   name  exactly one receiver? Does  receiver   name  exactly one sender?
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
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
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
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
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
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
Channels, Ports, and Mailboxes Allow  indirect  communication: Senders/Receivers name  channel   instead  of  processes Senders/Receivers determined at  runtime Sender  does  not  need to know  who receives  the message Receiver  does  not  need to know  who sent  the message
Named Message Channels Named Pipe (Win32) P1: . . . . . . . . send(ch1, msg1); . . . . . . . . P2: . . . . . . . . send(ch2, msg2); . . . . . . . . P3: . . . . . . . . receive(ch1, x); . . . . . . . . receive(ch2, y); . . . . . . . . ch1 ch2
CSP/Occam Using  Named channel , say,  ch1  to connect processes, say,  p1  and  p2 p1  sends to  p2  using:  send( ch1 , ’a’ ) p2  receives from  p1  using:  receive( ch1 , x ) Guarded commands: when ( c )  s   Set of statements  s  executed only  when  c  is true Allow processes to  receive messages selectively  based on arbitrary conditions CSP: Communicating Sequential Processes Occam: a Language
Bounded buffer with CSP Communicating Sequential Processes: Buffer  B Producer  P Consumer  C Problems:  When Buffer  full :  B  can only send to  C When Buffer  empty :  B  can only receive from  P When Buffer  partially   filled :  B  must know  whether  C  or  P  is ready to act Solution: C  sends  request  to  B  first;  B  then sends data Inputs from  P  and  C  are guarded with  when B P C
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,data) receive(request) send(remove,data) receive(deposit, data)
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.
Bounded buffer with CSP process BoundedBuffer {  char buf[n]; int nextin=0, nextout=0, count=0;  while (1) { when ((count<n) && receive(deposit, buf[nextin])){  nextin = (nextin + 1) % n;  count = count + 1;  }  or  when ((fullCount>0) && receive(reqest)){    send(remove, buf[nextout]);    nextout = (nextout + 1) % n;    count = count - 1;  } }  } 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.
Bounded buffer with CSP process BoundedBuffer {  char buf[n]; int nextin=0, nextout=0, count=0;  while (1) { when ((count<n) &&  receive ( deposit , buf[nextin])){  nextin = (nextin + 1) % n;  count = count + 1;  }  or  when ((fullCount>0) && receive(reqest)){    send(remove, buf[nextout]);    nextout = (nextout + 1) % n;    count = count - 1;  } }  } Pass data to the consumer if it has requested one.
Bounded buffer with CSP process BoundedBuffer {  char buf[n]; int nextin=0, nextout=0, count=0;  while (1) { when ((count<n) &&  receive ( deposit , buf[nextin])){  nextin = (nextin + 1) % n;  count = count + 1;  }  or  when ((count>0) &&  receive ( request )){    send ( remove , buf[nextout]);    nextout = (nextout + 1) % n;    count = count - 1;  } }  }
More on Named Channels Each  named channel  serves for a  particular purpose . Processes  are  connected  through named channels  directly . Buffer Producer Consumer deposit request remove
Ports and Mailboxes Port Mailboxes
Ports and Mailboxes Processes are connected through  intermediary . Allowing a receiver to  receive from multiple senders  (nondeterministically). Sending can be  nonblocking . The intermediary usually is a  queue . The queue is called  mailbox  or  port , depending on number of receivers: mailbox  can have  multiple   senders  and  receivers port  can have only  one   receiver
Ports and Mailboxes
Procedure-Based Communication Send/Receive  are too  low  level (like  P/V ) Typical interaction among processes:  Send  Request & (then)  Receive  Result. Make this into a  single higher-level primitive. Use  RPC  (Remote Procedure Call) or  Rendezvous Caller  invokes procedure  on  remote  machine. Remote  machine  performs operation  and returns result. Similar to  regular procedure call , but parameters  cannot  contain  pointers  because caller and server do not share any memory.
Procedure-Based Communication Send/Receive  are too  low  level (like  P/V ) Typical interaction among processes:  Send  Request & (then)  Receive  Result. Make this into a  single higher-level primitive. Use  RPC  (Remote Procedure Call) or  Rendezvous Caller  invokes procedure  on  remote  machine. Remote  machine  performs operation  and returns result. Similar to  regular procedure call , but parameters  cannot  contain  pointers  because caller and server do not share any memory. In fact, it ` can ’ by doing  marshalling  on parameters.
RPC Caller issues:  res = f( params ) This is translated into: 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);  } }
Rendezvous With  RPC :  Called process  p  is part of a dedicated  server Setup is  asymmetrical      Client-sever   relation With  Rendezvous : p  is part of an arbitrary process p  maintains state between calls p  may accept/delay/reject call Setup is  symmetrical : Any process may be a  client   or  a  server “ Rendezvous ” is French for “ meeting .” Pronunciation    “ RON-day-voo .”
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
Semantics of a Rendezvous Caller or Server  waits  for  the other . Then, they execute in  parallel .
Semantics of a Rendezvous p q Rendezvous p q Rendezvous q . f () accept  f () S q . f () accept  f () S
Rendezvous: Selective Accept select { [when B1:]  accept  E1 (…) S1; or [when B2:]  accept  E2 (…) S2; or . . . or [when Bn:]  accept  En (…) Sn; [else R] } Ada provides a select statement that permits  multiple   accepts  (guarded or not) to be active simultaneous. Only one could be selected  nondeterministically  upon Rendezvous.
Rendezvous: Selective Accept [. . .] : optional select { [when B1:]  accept  E1 (…) S1; or [when B2:]  accept  E2 (…) S2; or . . . or [when Bn:]  accept  En (…) Sn; [else R] }
Example: Bounded Buffer process  BoundedBuffer  { char buffer[n]; int nextin=0, nextout=0, count=0;  while(1) {  select  {  when (fullCount < n):   accept   deposit (char c) {  buffer[nextin] = c;  nextin = (nextin + 1) % n;  count = count + 1;  }  or  when (count > 0):   accept   remove (char c) {  c = buffer[nextout];  nextout = (nextout + 1) % n;  count = count - 1;  }  } } }  To provide the following services forever: deposit remove
Example: Bounded Buffer process  BoundedBuffer  { char buffer[n]; int nextin=0, nextout=0, count=0;  while(1) {  select  {  when (count < n):   accept   deposit (char c) {  buffer[nextin] = c;  nextin = (nextin + 1) % n;  count = count + 1;  }  or  when (count > 0):   accept   remove (char c) {  c = buffer[nextout];  nextout = (nextout + 1) % n;  count = count - 1;  }  } } }
Example: Bounded Buffer BoundedBuffer .deposit(data) BoundedBuffer .remove(data)
Distributed Mutual Exclusion CS  problem in a Distributed Environment No   shared memory ,  No   shared clock , Delays  in message transmission . Central Controller Solution Requesting process sends request to  controller Controller  grant  it to  one processes at a time Problems: Single point of  failure ,  Performance  bottleneck Fully Distributed Solution: Processes  negotiate  access among  themselves Very complex
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; Controler[1]: P[1]: CS1; Program1; token token RequestCS ReleaseCS RequestCS ReleaseCS RequestCS ReleaseCS
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;  } } Do four possible jobs: Receive token Transmit token Lock token ( RequestCS ) Unlock token ( ReleaseCS ) token token RequestCS ReleaseCS RequestCS ReleaseCS RequestCS ReleaseCS
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
Operating Systems Principles Process Management and Coordination Lecture 3: Higher-Level Synchronization and Communication Other Classical Problems
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 Extension  of basic CS problem (Courtois, Heymans, and Parnas, 1971) Two types  of  processes  entering a CS: Only  one  Writer   (W)  may be inside CS, (exclusive) or Many   Readers (Rs)  may be inside CS Prevent   starvation  of either process type: If  Rs  are in CS, a  new   R  must  not  enter if  W  is waiting If  W  is in CS, once it leaves,  all   Rs  waiting should enter (even if they arrived after new  Ws )
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.
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.
Dining Philosophers
Dining Philosophers Five philosophers  sit around a circular table.  In the centre of the table is a large plate of  spaghetti . Each philosopher spends his life alternatively  thinking  and  eating .  A philosopher needs  two  forks to eat.  Requirements Prevent   deadlock Guarantee  fairness :   no  philosopher must  starve Guarantee  concurrency : non-neighbors may eat  at the same time
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]); return_forks (i): V(f[i]); V(f[(i+1)%5]); Easily lead to  deadlock .
Solutions to deadlock Use a  counter : At most   n    1  philosophers may attempt to grab forks. One  philosopher requests forks in  reverse  order, e.g.,  grab_forks (1):  P (f[2]);  P (f[1]); Divide philosophers into  two groups : Odd  grab  Left  fork  first ,  Even  grab  Right  fork  first
Logical Clocks Many applications need to  time-stamp  events  for  debugging , recovery, distributed mutual exclusion, ordering of broadcast messages,  transactions , etc. Time-stamp allows us to determine the  causality  of events. C(e1)<C(e2)  means  e 1  happened before  e2 . Global clock  is  unavailable  for distributed systems. Physical clocks  in distributed systems are  skewed .
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!
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 The simple algorithm by which a single elevator can  decide  where to stop  is: Continue traveling  in the same direction while there are remaining requests in  that same direction .  If there are no further requests then  change direction . Scheduling  hard disk  requests.
The Elevator Algorithm
The Elevator Algorithm Pressing button  at floor  i  or button   i  inside elevator invokes:  request(i) Door closing , invokes:  release() Scheduler policy: direction  =  up : it services all requests  at or  above  current position; then it reverses direction direction  =  down : it services all requests at or  below  current position; then it reverses direction request ( i ) request ( i ) direction  =  up driection  =  down
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 .
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*/ . . . . . . . . . . . . . . . }  }
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;  }  }  } }

More Related Content

PDF
C++ control structure
PPTX
11 lec 11 storage class
DOCX
Import java
PPTX
Looping Structures
PPT
Java Programming: Loops
DOCX
Programming Fundamentals lecture 8
PPT
Storage classes
PDF
A formalization of complex event stream processing
C++ control structure
11 lec 11 storage class
Import java
Looping Structures
Java Programming: Loops
Programming Fundamentals lecture 8
Storage classes
A formalization of complex event stream processing

What's hot (20)

PPTX
Storage class in C Language
PPTX
Semaphore
PPTX
C++ loop
PDF
Checking Wine with PVS-Studio and Clang Static Analyzer
PPT
Storage classes
PPT
storage class
PPTX
Loop control in c++
PPTX
Storage class
PPTX
Storage class in c
PPTX
The System of Automatic Searching for Vulnerabilities or how to use Taint Ana...
PPT
C++ control loops
PPTX
Storage classes in C
DOCX
Java loops
PPT
06 Loops
PPTX
Storage classes in C
PPTX
Storage classes
PPTX
Storage Class in C Progrmming
PPT
Looping statements in Java
PPT
STORAGE CLASSES
Storage class in C Language
Semaphore
C++ loop
Checking Wine with PVS-Studio and Clang Static Analyzer
Storage classes
storage class
Loop control in c++
Storage class
Storage class in c
The System of Automatic Searching for Vulnerabilities or how to use Taint Ana...
C++ control loops
Storage classes in C
Java loops
06 Loops
Storage classes in C
Storage classes
Storage Class in C Progrmming
Looping statements in Java
STORAGE CLASSES
Ad

Viewers also liked (20)

PDF
adaptive signal control technology along sw 8th street pilot project
PDF
COORDINATION OF ACTUATED SIGNALS FOR A CORRIDOR
PPT
Machine Learning and Optimization For Traffic and Emergency ...
PDF
Brandon Signals Council Presentation
PDF
Urban Traffic Estimation & Optimization: An Overview
PPT
PTV Vissig Optimisation Share
PDF
Future of intelligent transportation CIO Roundtable 080214
PPT
Os4 2
PPT
Os6
PPT
Class5
PPT
Os4
PPT
Ch11 input output systems
PPT
Os5 2
PPT
Os2 2
PDF
Lecture 7: Definite Clause Grammars
PPT
Os6 2
PPT
Os2
PPT
Class9
PDF
Design1
PDF
Adaptive Traffic Control Systems Overview
adaptive signal control technology along sw 8th street pilot project
COORDINATION OF ACTUATED SIGNALS FOR A CORRIDOR
Machine Learning and Optimization For Traffic and Emergency ...
Brandon Signals Council Presentation
Urban Traffic Estimation & Optimization: An Overview
PTV Vissig Optimisation Share
Future of intelligent transportation CIO Roundtable 080214
Os4 2
Os6
Class5
Os4
Ch11 input output systems
Os5 2
Os2 2
Lecture 7: Definite Clause Grammars
Os6 2
Os2
Class9
Design1
Adaptive Traffic Control Systems Overview
Ad

Similar to Os3 2 (20)

PPT
Os3
PPT
Inter process communication
PDF
Operating Systems 3rd Edition Nutt Solutions Manual
PPTX
B.Tech. Computer Science Engineering OS Notes Unit 2
PDF
Operating Systems 3rd Edition Nutt Solutions Manual
PPTX
Interprocess Communication important topic in iOS .pptx
PDF
Operating Systems 3rd Edition Nutt Solutions Manual
PDF
Operating Systems 3rd Edition Nutt Solutions Manual
PDF
Operating Systems 3rd Edition Nutt Solutions Manual
PPTX
Chapter05 new
PPTX
Full solution to bounded buffer
PDF
PART-3 : Mastering RTOS FreeRTOS and STM32Fx with Debugging
PDF
Indirect Communications (Concurrency)
DOCX
Concurrency : Mutual Exclusion and Synchronization
PDF
Lecture 3_Processes in Operating Systems.pdf
PPT
Semaphores and Monitors
PPTX
Chapter 6 Concurrency: Deadlock and Starvation
PPT
Intro Basic of OS .ppt
PPT
Classic synchronization
PPT
LEC_3.ppt jef,fdds,fn,befhj efbhjfrgeukevbhwj
Os3
Inter process communication
Operating Systems 3rd Edition Nutt Solutions Manual
B.Tech. Computer Science Engineering OS Notes Unit 2
Operating Systems 3rd Edition Nutt Solutions Manual
Interprocess Communication important topic in iOS .pptx
Operating Systems 3rd Edition Nutt Solutions Manual
Operating Systems 3rd Edition Nutt Solutions Manual
Operating Systems 3rd Edition Nutt Solutions Manual
Chapter05 new
Full solution to bounded buffer
PART-3 : Mastering RTOS FreeRTOS and STM32Fx with Debugging
Indirect Communications (Concurrency)
Concurrency : Mutual Exclusion and Synchronization
Lecture 3_Processes in Operating Systems.pdf
Semaphores and Monitors
Chapter 6 Concurrency: Deadlock and Starvation
Intro Basic of OS .ppt
Classic synchronization
LEC_3.ppt jef,fdds,fn,befhj efbhjfrgeukevbhwj

More from issbp (17)

PPT
Os10 2
PPT
Os10
PPT
Os9 2
PPT
Os9
PPT
Os8 2
PPT
Os8
PPT
Os7 2
PPT
Os7
PPT
Os5
PPT
Class8
PPT
Class7
PPT
Class6
PPT
Class4
PPT
Class3
PPT
Class2
PPT
Class1
PPT
0227 regularlanguages
Os10 2
Os10
Os9 2
Os9
Os8 2
Os8
Os7 2
Os7
Os5
Class8
Class7
Class6
Class4
Class3
Class2
Class1
0227 regularlanguages

Os3 2

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