Reputation: 3479
I'm trying to understand how the R-V in ADA works:
server (pseudo)code:
task test is
entry put (num: in integer);
entry get (num: out integer);
end test;
task body test is
local_num: integer;
begin
accept put (num: in integer) do
local_num := num;
end put;
// some next processing of local_num, eg:
local_num := local_num * 2;
accept get (num: out integer) do
num := local_num;
end get;
end test;
and the client a server are communicating as following:
client (a) | server (b)
================================
| // sleep
(call_entry) | // sleep
a.put(num) | // sleep
// sleep | (accept_entry)
// sleep | b.accept put(num)
// sleep | local_num := num;
// sleep | local_num := local_num * 2;
| ??? <--------------------- what is happening after that point?
(call_entry) | // sleep
a.get(num) | // sleep
// sleep | (accept_entry)
// sleep | b.accept get(num)
update: (correct process?)
client | server (test)
================================
test.put(num) | // sleep ----------> call entry
test.get(A) | accept put(num) ----------> accept entry PUT (call entry GET to the QUEUE)
// sleep | local_num := num;
// sleep | local_num := local_num * 2;
test.get(A) | accept get(A) ----------> accept entry (removed from the QUEUE)
| // sleep
Upvotes: 1
Views: 3617
Reputation: 37616
Ada Rendez-Vous are really simple, in fact you have a task test
with 2 entries get
and put
. Once you run the program, the test
task is started, so the local_num
value is created (with no defined initial value) and the body
is executed BUT the first statement is an accept
so the task is waiting for an entry call.
procedure ... is
task test is
...
end test ;
task body test is
...
end test ;
A : Integer ;
begin
-- 1. The 'test' task is started here, waiting for a call to `put`
-- 2. You call the 'put' entry, which mean that the current task (the main task)
-- is stopped until the end of the entry call.
test.put(33) ;
-- 3. Here the entry 'put' is finished, so the 2 tasks are executing
-- simultaneously
-- 4. Here we call the 'get' entry, there is a non predictive behaviour:
-- We do not know if the instruction local_num := local_num * 2; has
-- been executed or not, so 2 case:
-- - The instruction has been executed, so the 'test' task is waiting
-- and directly accept the 'get' entry, while the main task wait
-- - The instruction has not been executed, so the main 'task' wait
-- until there is someone to accept is call
-- What you're sure is that the entry 'get' won't be executed before
-- the instruction, and that someone calling 'get' will have to wait
-- until the 'test' task get to the 'accept get' instruction.
test.get(A) ;
-- 5. Here, the 'get' entry is finished, so you're sure that you have ended
-- the 'test' task
end ... ;
In fact, when you call a entry like test.get
, you loose the control until the test.get
entry has been fully executed. If there is no task waiting for this entry, you will wait until a task request this entry.
procedure BadTask is
-- Stupid task that will accept a 'put' entry and then a 'get' (only once)
task T is
entry get (A : out Integer);
entry put (A : in Integer);
end T ;
task body T is
LocalInteger : Integer := 0 ;
begin
accept put (A : in Integer) do
LocalInteger := A ;
end put ;
accept get (A : ouInteger) do
A := LocalInteger ;
end get ;
end T ;
A : Integer ;
begin
-- Here T is waiting for 'put'
T.get (A) ;
-- You will never get here and your program is blocked because the two tasks
-- are waiting but no one can't get the control.
end BadTask ;
Upvotes: 3