Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between statements inside and outside accept block

Tags:

ada

Suppose the following (server) task specification:

task type Server_Task is
      entry E1(I: Integer);
      entry E2;
      entry E3;
end Server_Task;

with a (dummy) implementation of:

task body Server_Task is      
   begin
      loop
         select
            accept E1(I: Integer) do
               -- statements inside E1 using I
               -- statements inside E1 using I
               -- statements inside E1 using I
               null;
            end;                       
         or
            accept E2 do
               null;               
            end;
         or
            accept E3 do
               null;
            end; 
         end select;         
      end loop;     
end Server_Task;

Based on my understanding, if a client task makes an entry call for (say) E1 then all statements inside the E1 accept block will be executed before the server task loops over again and is ready to accept another entry call. The same is true if there are further statements following the end of the accept block so that again all these will need to run before the task can randevouz with a calling task again. If that assumption is correct, I'm wondering what the behavioural difference is between the above implementation and the one below:

task body Server_Task is
      Temp: Integer;
   begin
      loop
         select
            accept E1(I: Integer) do
               Temp := I;       
            end;
            -- statements outside E1 using Temp
            -- statements outside E1 using Temp
            -- statements outside E1 using Temp
         or
            accept E2 do
               null;               
            end;
         or
            accept E3 do
               null;
            end; 
         end select;         
      end loop;     
end Server_Task;

Will there be a difference if the statements outside E1 make a blocking call and hence the server task is suspended and therefore these statements will then have to somehow compete with any other entry calls made by the task's clients? (though this doesn't make much sense if the task is implemented using just one "thread"?)

For the sake of argument suppose the client code is along the lines of:

ST: Server_Task;   
   task body Client_Task is
   begin
      select
         ST.E2;
      else
         -- do something else
         null;
      end select;
      null;
   end Client_Task;

Is this behaviour detailed somewhere in the ARM? - Thanks

like image 944
Sidisyom Avatar asked Jan 21 '26 14:01

Sidisyom


1 Answers

The big difference is that both the server and the client are locked into waiting on that accept statement to complete before moving on. You are correct that in both cases the server is still running the same code essentially regardless of position. But in the first case, the client is waiting there for those statements to complete while in the second case the client can move on and do other stuff while those statements after the accept go.

There are pros/cons to both scenarios. In the first, you have the capability of doing operations that are protected from data races for the client, while in the second case, if those statements adjust global/shared data then you open yourself up to data races since both client and server can operate on that data.

That said, I prefer the 2nd scenario for most cases, only falling back to the 1st when I need to protect data. The main reason is it frees up the client to do other work instead of waiting.

        accept E1(I: Integer) do
           -- statements inside E1 using I
           -- statements inside E1 using I
           -- statements inside E1 using I
           null;
        end;  -- Client is free

vs

        accept E1(I: Integer) do
           null;
        end;  
        -- Client is free everything after is potentially unsafe 
        -- for client, but the client can do other things quicker
        -- statements inside E1 using I
        -- statements inside E1 using I
        -- statements inside E1 using I
             

For your third part: That select is basically only checking for the Rendezvous to start. Once the rendevous starts, you are in there as far as the client is concerned. The "else" part only applies while waiting for the rendezvous to even occur.

For blocking statements "after" the rendezvous, those will delay or prevent the next rendezvous from occuring until they resolve. They won't affect the client directly unless it is making another rendezvous to the same task later or to a protected object entry that both tasks share. At that point though, your "ELSE" in the select statement will be chosen since the client can't re-enter the rendezvous until the server finishes the blocking tasks and gets back to the accept statement code.

All of this is detailed in the arm. I don't know the sections offhand, but look for the tasking section in the table of contents or look up select statement in the index.

like image 113
Jere Avatar answered Jan 24 '26 13:01

Jere