Your SlideShare is downloading. ×
Os3 2
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Os3 2

550
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
550
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 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
  • 67. Ports and Mailboxes
  • 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
  • 86. Readers/Writers Problem Database
  • 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.
  • 92. Dining Philosophers
  • 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.
  • 101. The Elevator Algorithm
  • 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; } } } }