Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to implement a non-blocking server in Ada?

Tags:

ada

My current design looks like this

task body Agent_Task is
begin
    loop
        select
            accept Request_A do
            end Request_A;
        or
            accept Request_B do
            end Request_B;
        or
            ...
        else
            Do_Other_Stuff;
        end select;

    end loop;
exception
      when Exception_Id : others => Show_Exception (Exception_Id);
end Agent_Task;

But when calling an entry in an agent frequently (e.g. Request_A) it will become non-responsive. Is there a better structure to make the agent never be blocked? like interrupts?

The most time consuming part is in Do_Other_Stuff, what I want the server to do is roughly:

loop
    Do_Other_Stuff;
    if interrupted, handle other requests.
end loop;

This a school assn which I can not modify the test program to retry a failed request to an agent. When the test is runing, mutilple agents will talk to each other concurrently.

like image 254
Mzq Avatar asked Oct 22 '21 05:10

Mzq


Video Answer


2 Answers

Note that you have a spurious end; in your code that makes it illegal.

If what's important is that those making requests not block, you could use a protected queue for the inter-task communication:

loop
   select
      Request_Queue.Get (Item => Request);
      Process (Request => Request);
   else
      Do_Other_Stuff;
   end select;
end loop;

Requests will not be processed until Do_Other_Stuff completes, but those making requests will not be blocked by putting a request on the queue.

Using a queue would also allow you to use asynchronous transfer of control to give requests priority over Do_Other_Stuff:

loop
   select
      Request_Queue.Get (Item => Request);
      Process (Request => Request);
   then abort
      Do_Other_Stuff;
   end select;
end loop;

Do_Other_Stuff would then need to be abortable, and able to pick up from where it left off the next time it runs. But it would be better if Do_Other_Stuff could be moved into another task as Holsti suggested.

Finally, if you can't move Do_Other_Stuff to another task, and you can't abort it, you may need to break it into shorter parts:

loop
   Do_Some_Stuff;
   Handle_Requests;
   Do_Some_More_Stuff;
   Handle_Requests;
   ..
end loop;

Again, this is easier with a queue, since accept statements can't go in a subprogram.

like image 155
Jeffrey R. Carter Avatar answered Oct 29 '22 09:10

Jeffrey R. Carter


Move the Do_Other_Stuff to another task, that is, divide your Agent_Task into two tasks.

How difficult that is depends on how much communication (data flow) there is between Do_Other_Stuff and the actions for Request_A and Request_B. If Do_Other_Stuff is moved to its own task, that task has to communicate with the original Agent_Task is some way, by rendez-vous or protected objects. If Do_Other_Stuff is a long computation that has some inputs and some outputs, you might add two entries to Agent_Task, one to provide the inputs to the Other_Stuff task, and another to receive the outputs from the Other_Stuff task.

like image 41
Niklas Holsti Avatar answered Oct 29 '22 11:10

Niklas Holsti