Entries & Rendezvous
Declare task entries, accept them with accept statements (with and without bodies), understand the rendezvous as synchronized communication with parameters, write server loops with select, use 'Count, and handle Tasking_Error when calling terminated tasks.
Tasks communicate directly through entries. A caller calls an entry like a procedure; the called task executes an accept statement for it. Whichever arrives first waits for the other — this meeting is the rendezvous. During the accept body the caller is suspended, parameters are exchanged, and then both continue independently. It is synchronous message passing with type-checked parameters.
Entries and accept
Entries are declared in the task specification: 'task Accumulator is entry Add (Value : Integer); entry Get_Total (Total : out Integer); end Accumulator;'. The task body accepts them: 'accept Add (Value : Integer) do Sum := Sum + Value; end Add;'. The statements between do and end run during the rendezvous; statements after end Add run after the caller is released, in parallel with it. 'accept Shutdown;' without a body is a pure synchronization point. Entry parameters use in / out / in out modes like procedures. Entry families ('entry Request (Priority_Level) (...)') provide arrays of entries.
• entry E (params); in the task spec. • accept E (params) do ... end E; — rendezvous body; caller waits. • Keep accept bodies short; do the work afterwards. • Entry families: entry E (Index_Type) (params).
Server Loops
A typical server task loops forever over a select statement offering several accepts: 'loop select accept Add ... or accept Get_Total ... or accept Shutdown; exit; end select; end loop;'. The select waits until any of the open alternatives has a caller. Callers queue FIFO per entry; E'Count (inside the task) gives the queue length. Calling an entry of a task that has terminated (or terminates while you wait) raises Tasking_Error in the caller.
• loop select accept A ... or accept B ... end select; end loop; • FIFO queue per entry; E'Count = waiting callers. • Calling a terminated task → Tasking_Error.
Code Examples
Main makes five Add calls (10 + 20 +... + 50 = 150), reads the total, signals Starter, then shuts down the accumulator. The shutdown message is printed inside the accept body, so it appears before main continues. Starter has already terminated, so the second Go raises Tasking_Error. Output: Total from Accumulator: 150 Starter received: hello from main Accumulator: shutting down after 5 Add calls Accumulator terminated: TRUE Calling a terminated task raised Tasking_Error accept Request (Data: Item) do Process (Data); -- long computation while the caller is blocked end Request;
accept Request (Data : Item) do Local := Data; end Request; Process (Local);
Copy parameters and release the caller quickly; do long work outside the rendezvous.
-- two tasks each calling the other's entry inside an accept -- design a clear client/server direction or use protected objects Circular entry calls deadlock.
Server.Stop; -- after Server has terminated, no handler begin Server.Stop; exception when Tasking_Error => null; end; -- or check Server'Callable
Calls to terminated tasks raise Tasking_Error.
During a rendezvous, what does the caller do? A. Continues in parallel B. Waits until the accept body completes C. Terminates D. Polls
Where do statements after 'end Add;' run? A. In the caller B. In the server task, after releasing the caller C. Never D. At program end
What does calling an entry of a terminated task raise? A. Program_Error B. Tasking_Error C. Constraint_Error D. Nothing
In which order are callers of the same entry served? A. Random B. FIFO (by default) C. LIFO D. By priority only
B. FIFO (priority queuing can be selected with Queuing_Policy).
Trace the rendezvous example.
Real output: Total from Accumulator: 150 Starter received: hello from main Accumulator: shutting down after 5 Add calls Accumulator terminated: TRUE Calling a terminated task raised Tasking_Error
with Ada.Text_IO; use Ada.Text_IO;
procedure L53_Rendezvous is
-- A server task offering entries
task Accumulator is
entry Add (Value : Integer);
entry Get_Total (Total : out Integer);
entry Shutdown;
end Accumulator;
task body Accumulator is
Sum : Integer := 0;
Calls : Natural := 0;
begin
loop
select
accept Add (Value : Integer) do
Sum := Sum + Value; -- runs while the caller waits (rendezvous)
end Add;
Calls := Calls + 1; -- runs after the caller is released
or
accept Get_Total (Total : out Integer) do
Total := Sum;
end Get_Total;
or
accept Shutdown do -- printed while main is still waiting
Put_Line ("Accumulator: shutting down after" & Natural'Image (Calls) & " Add calls");
end Shutdown;
exit;
end select;
end loop;
end Accumulator;
-- A task that waits for a start signal: synchronization without data
task Starter is
entry Go (Message : String);
end Starter;
task body Starter is
begi
…