Rendezvous

Revision as of 14:23, 17 February 2009 by rosettacode>Dmitry-kazakov (Redezvous)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Rendezvous is a synchronization mechanism based on procedural decomposition. Rendezvous is similar to a procedure call with the difference that the caller and the callee belong to different tasks. The called procedure is usually called an entry point of the corresponding task. A call to an entry point is synchronous, i.e. the caller is blocked until completion. For the caller a call to the entry point is indivisible. Internally it consists of:

  • Waiting for the callee ready to accept the rendezvous;
  • Engaging the rendezvous (servicing the entry point).
Task
Rendezvous
You are encouraged to solve this task according to the task description, using any language you may know.

The caller may limit the waiting time to the callee to accept the rendezvous. I.e. a rendezvous request can be aborted if not yet accepted by the callee. When accepted the rendezvous is processed until its completion. During this time the caller and the callee tasks stay synchronous. Which context is used to process the rendezvous depends on the implementation which may wish to minimize context switching.

The callee task may accept several rendezvous requests:

  • Rendezvous to the same entry point from different tasks;
  • Rendezvous to different entry point.

The callee accepts one rendezvous at a time.

Language mechanism of exceptions (if any) is consistent with the rendezvous. In particular when an exception is propagated out of a rendezvous it shall do in both tasks. The exception propagation is synchronous within the rendezvous and asynchronous outside it.

A rendezvous can be requeued to by the callee to another entry point of its task or to another task, transparently to the caller.

Differently to messaging which are usually asynchronous, rendezvous are synchronous, as it was stated before. Therefore a rendezvous does not require marshaling. It is also can be implemented without context switch. This makes rendezvous a more efficient than messaging.

Rendezvous can be used to implement monitor synchronization objects. A monitor guards a shared resource. All users of the resource requests a rendezvous to the monitor in order to get access to the resource. Access is granted by accepting the rendezvous for the time while the rendezvous is serviced.

Language task

Show how rendezvous are supported by the language. If the language does not have rendezvous, provide an implementation of.

Use case task

Implement a printer monitor. The monitor guards a printer. There are two printers main and reserve. Each has a monitor that accepts a rendezvous Print with a text line to print of the printer. The standard output may serve for printing purpose. Each character of the line is printed separately in order to illustrate that lines are printed indivisibly. Each printer has ink for only 5 lines of text. When the main printer runs out of ink it redirects its requests to the reserve printer. When that runs out of ink too, Out_Of_Ink exception propagates back to the caller. Create two writer tasks which print their plagiarisms on the printer. One does Humpty Dumpty, another Mother Goose.

Ada

Ada has integrated rendezvous support. The caller calls to a rendezvous using the name of the task suffixed by the entry point name and the parameters. An entry point can be called using timed entry call statement which allow limit waiting time: <lang ada> select

  Server.Wake_Up (Parameters);

or delay 5.0;

  -- No response, try something else
  ...

end select; </lang> The task accepts a rendezvous using accept statement. The statement can contain body which implements the rendezvous. When several rendezvous need to be accepted a selective accept statement can be used. For example: <lang ada> select

  accept Wake_Up (Parameters : Work_Item) do
     Current_Work_Item := WI;
  end;
  Process (Current_Work_Item);

or accept Shut_Down;

  exit;       -- Shut down requested

end select; </lang> Entry points in the selective accept can be guarded by Boolean expressions which close the entry point when the expression yield false.

A task may requeue rendezvous request from the body of an accept statement to an entry point of the same or another task if the parameter profile of the entry point is compatible. The requeue statement may contain clause 'with abort which allows the caller to abort the request when it waits for other task to accept it. Without the clause the request is protected from abortion. This might be useful when the first task initiates processing of the request and the side effect of this action need to be removed when processing is completed.

The task

<lang ada> with Ada.Text_IO; use Ada.Text_IO;

procedure Rendezvous is

  Out_Of_Ink : exception;
  type Printer;
  type Printer_Ptr is access all Printer;
  task type Printer (ID : Natural; Backup : Printer_Ptr) is
     entry Print (Line : String);
  end Printer;
  task body Printer is
     Ink : Natural := 5;
  begin
     loop
        begin
           select
              accept Print (Line : String) do
                 if Ink = 0 then
                    if Backup = null then
                       raise Out_Of_Ink;
                    else
                       requeue Backup.Print with abort;
                    end if;
                 else
                    Put (Integer'Image (ID) & ": ");
                    for I in Line'Range loop
                       Put (Line (I));
                    end loop;
                    New_Line;
                    Ink := Ink - 1;
                 end if;
              end Print;
           or terminate;
           end select;
        exception
           when Out_Of_Ink =>
              null;
        end;
     end loop;
  end Printer;
  Reserve : aliased Printer (2, null);
  Main    : Printer (1, Reserve'Access);
  
  task Humpty_Dumpty;
  task Mother_Goose;
  
  task body Humpty_Dumpty is
  begin
     Main.Print ("Humpty Dumpty sat on a wall.");
     Main.Print ("Humpty Dumpty had a great fall.");
     Main.Print ("All the king's horses and all the king's men");
     Main.Print ("Couldn't put Humpty together again.");
  exception
     when Out_Of_Ink =>
        Put_Line ("      Humpty Dumpty out of ink!");
  end Humpty_Dumpty;
  task body Mother_Goose is
  begin
     Main.Print ("Old Mother Goose");
     Main.Print ("When she wanted to wander,");
     Main.Print ("Would ride through the air");
     Main.Print ("On a very fine gander.");
     Main.Print ("Jack's mother came in,");
     Main.Print ("And caught the goose soon,");
     Main.Print ("And mounting its back,");
     Main.Print ("Flew up to the moon.");
  exception
     when Out_Of_Ink =>
        Put_Line ("      Mother Goose out of ink!");
  end Mother_Goose;

begin

  null;   

end Rendezvous; </lang> Sample output:

 1: Old Mother Goose
 1: Humpty Dumpty sat on a wall.
 1: When she wanted to wander,
 1: Humpty Dumpty had a great fall.
 1: Would ride through the air
 2: All the king's horses and all the king's men
 2: On a very fine gander.
 2: Couldn't put Humpty together again.
 2: Jack's mother came in,
 2: And caught the goose soon,
      Mother Goose out of ink!