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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With