Ada - How to implement an asynchronous task that allows the main thread to poll it? - task

I want to create a task that reads from a file for a few minutes while the main thread does other things. But I'd like the main thread to be able to poll the task to see if it is "Busy" or not (a Boolean value) without blocking the main thread.
I have a naive attempt here, which does work but it leaves the Busy flag completely exposed to be toggled at will by the main thread (this is not safe)...
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task type Non_Blocking_Reader_Task (Busy : access Boolean) is
entry Read (Destination : in Natural);
end Non_Blocking_Reader_Task;
task body Non_Blocking_Reader_Task is
begin
loop
select
when not Busy.all =>
accept Read (Destination : in Natural) do
Busy.all := True;
end Read;
for i in 1 .. 50 loop
Put ("."); -- pretend to do something useful
delay 0.1; -- while wasting time
end loop;
Busy.all := False;
end select;
end loop;
end Non_Blocking_Reader_Task;
Reader_Busy_Volatile : aliased Boolean;
Reader : Non_Blocking_Reader_Task (Reader_Busy_Volatile'Access);
begin
Put_Line (Reader_Busy_Volatile'Image);
Reader.Read (123);
for i in 1 .. 15 loop
Put_Line (Reader_Busy_Volatile'Image);
delay 0.5;
end loop;
abort Reader;
end Main;
My second idea was to create a protected type and hide the flag and the task inside it, but this is not permitted by the language.
Question
How can I create a protected "task is busy" flag that can is read-only from the main thread and read/write from the task (which does not cause the main thread to block)?
Edit:
The solution!
My revised (working) solution based on the stirling advice of #flyx :)
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task type Reader_Task is
entry Read (Destination : in Natural);
entry Join;
entry Ready;
end Reader_Task;
task body Reader_Task is
Dest : Natural;
begin
loop
select
accept Read (Destination : in Natural) do
Dest := Destination;
end Read;
-- we only get here after a Read has been received.
for i in 1 .. 5 loop
Put ("."); -- pretend to do something useful
delay 1.0; -- while wasting time
end loop;
or
accept Join;
or
accept Ready;
or
terminate;
end select;
end loop;
end Reader_Task;
Reader : Reader_Task;
begin
-- first call will not block.
Reader.Read (123);
Put_Line ("MAIN: Reading in progress on second thread");
for i in 1 .. 12 loop
select
-- NON-BLOCKING CALL!
Reader.Ready; -- test if task is busy
Put_Line ("MAIN: NON-BLOCKING CALL SUCCEEDED -- TASK IS NOT BUSY");
else
Put_Line ("MAIN: NON-BLOCKING CALL FAILED -- TASK IS BUSY");
end select;
delay 1.0;
end loop;
Put_Line ("Main: Waiting for Reader (BLOCKING CALL)...");
Reader.Join;
Put_Line ("Main: all finished!");
end Main;
I've added two more entries to the task: Join and Ready which are basically the same but for the names. Join reminds me to do a blocking call to it, and Ready indicates that a non-blocking call is suitable for testing task availability. I've done this because there are times when I want to know if the previous run of Read() has finished without firing off a new one. This lets me do this neatly and all without any discrete flags at all! Awesome.

In Ada, the caller decides whether an entry call is blocking or not. You should not try and implement code for checking this inside the task.
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
task type Reader_Task is
entry Read (Destination : in Natural);
end Reader_Task;
task body Reader_Task is
begin
loop
select
accept Read (Destination : in Natural) do
null;
-- store Destination (?)
end Read;
or
-- allow task to be terminated while waiting
terminate;
end select;
-- we only get here after a Read has been received.
for i in 1 .. 50 loop
Put ("."); -- pretend to do something useful
delay 0.1; -- while wasting time
end loop;
end loop;
end Reader_Task;
Reader : Reader_Task;
begin
-- first call will not block.
Reader.Read (123);
for i in 1 .. 15 loop
-- check whether Read can be called immediately and if yes,
-- call it.
select
Reader.Read (456);
else
-- Read is not available, do something else.
null;
end select;
delay 0.5;
end loop;
-- don't call abort; let Reader finish its current task.
-- Reader will be terminated once it waits on the terminate alternative
-- since the parent is finished.
end Main;
The select … else … end select structure is Ada's way of doing a non-blocking call. You don't use a flag for signalling that the task is ready to receive an entry call because potentially, this state could change between the query of the flag and the actual call of the entry. select has been designed to avoid this problem.

Related

lua dynamically stop or manipulate a function

What I want to do is to dynamically stop a function in lua. My code that i tried:
local SaveReal = Thread
local stopped = false
--[[
Thread function runs the lua function
that it includes in a separate thread.
It was created before here
and is trying to be manipulated here.
]]--
Thread = function(func)
SaveReal(function()
while(not stopped) do
func()
end
end)
end
Thread(function()
while(true) do
print("Thread working")
end
end)
Maybe if I could read the contents of the function as a string, I could load it into my manipulative function with load. so the code would not work if my flag is not false.
Lua has something called Coroutines to provide multi-tasking (not multi-threading).

Ada - Task termination error - "Statement expected"

I have the following task
task body auto is
begin
Put_Line( licencepalte.all & " set off.");
delay traveltime.all;
Put_Line( licencepalte.all & " arrived.");
loop
select
indicator.passthrough;
terminate; -- error for this line: 'statement expected'
or
delay 0.2;
Put_Line( licencepalte.all & " is waiting.");
end select;
end loop;
end auto;
where we represent an indicator light and some cars (auto ~ automobiles) with tasks and protecteds. My main issue is, that I don't know, how to terminate, in case the indicator accepts the entry of the auto. You can see what I'm currently trying to do, and it pops up an error (see inline). How do I stop the task once the entry gets accepted? Why does this terminate not work? Thank you!
terminate is not an "action" that you perform. That is, you can't use a terminate statement anywhere you choose in the task body to terminate the task. The way to terminate a task is for the execution to reach the end that ends the body; in your case, exit to exit the loop works, as in Jacob's answer.
The purpose of or terminate is tell the program that a task is eligible for termination (I don't know if there's a better technical term for this). Suppose your task looks like:
task body Task_Type_1 is
begin
loop
select
accept Entry_1(...parameters...) do
-- something
end Entry_1;
or
accept Entry_2(...parameters...) do
-- something
end Entry_2;
end select;
end loop;
end Task_Type_1;
If the "something" code of the accept statements never exits the loop, the task will never terminate. This means that other constructs enclosing the task can never terminate. For example:
procedure Proc is
T1 : Task_Type_1;
begin
-- do some stuff
-- now we're at the end, and we have to wait for T1 to complete
end Proc;
The procedure creates a task of type Task_Type_1 and starts it. Then the body of the procedure is executed. When end Proc; is reached, the procedure doesn't terminate immediately, because it has to wait until the task finishes its job. But the way the task is written, the task will never complete. Therefore Proc will never return, and the program will probably deadlock.
or terminate is how to say that the task could terminate:
task body Task_Type_1 is
begin
loop
select
accept Entry_1(...parameters...) do
-- something
end Entry_1;
or
accept Entry_2(...parameters...) do
-- something
end Entry_2;
or
terminate;
end select;
end loop;
end Task_Type_1;
In this small example, where we have a procedure that just creates this one task, or terminate means: if this task reaches a point where it's blocked in the select because there aren't any entry calls waiting, and if Proc has reached the end of its code, then we terminate the task. The task body exits, any finalization that needs to be done is done, and then Proc can complete.
or terminate can be used only in a "selective accept". If you say select Some_Other_Task.Entry_2(...); so that it blocks until the other task's entry is available, you can't use or terminate in that kind of select.
In a more complex case, a procedure could create two or more tasks. When that procedure reaches its end statement, it won't return until (roughly speaking) all the tasks it creates are completed or all of the tasks that haven't completed are blocked on select statements that have or terminate clauses. If the latter happens, then all of those tasks complete and then the procedure can return.
The rule about "terminate alternatives" is in RM 9.3(6). It speaks in terms of depending on a master; in the example I showed above, Proc is the master.
If I understand your question correctly, an exit would do nicely instead of terminate.

how can i stop a lua function block/call mid execution

is there a way to stop a lua pcall to a lua function block from mid execution? Im using multiple threads and would be good to cancel a function mid-flight.
The simplest way is to call error('my message') as this will abort the execution and will return nil, 'my message' as the result of pcall(). If you want to abort a running coroutine (or a "main" chunk) from "outside", the only way to do it I know about without modifying Lua VM is to attach a debug hook to coroutine or the main chunk and call error() from that debug hook:
print(1)
local count = 0
debug.sethook(function(event, line)
if count > 1 then error('done', 2) end
count = count + 1
end, "l")
print(2)
print(3)
print("not getting here")
You should see something like this:
1
2
3
script.lua:4: done
In the case of pcall, you will see the parameter of the error() call to be passed as the error message by pcall.
The conditions to check can get quite elaborate; for example, you can check for the hook to be called from a particular function with a certain number of commands executed before aborting.

Rendezvous ADA - how it works

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)
Is it correct?
Can you describe me how it continues?
Who awakes the client to get the result? How the client know, that it can get the result?
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
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 ;

How to exit a Lua script's execution?

I want to exit execution of Lua script on some condition .
Example :
content = get_content()
if not content then
-- ( Here i want some kind of exit function )
next_content = get_content()
--example there can lot of further checks
Here I want that if I am not getting content my script suppose to terminate is should not go to check to next.
Use os.exit() or just return from some "main" function if your script is embedded.
os.exit()
kill process by sending a signal
do return end
stop execution
The two methods are not equal if you want to write and execute some luacode in the interpreter after stopping the execution by launching your program using the -i flag.
th -i main.lua
extract from the lua api doc :
For syntactic reasons, a break or return can appear only as the last statement of a block (in other words, as the last statement in your chunk or just before an end, an else, or an until). For instance, in the next example, break is the last statement of the then block.
local i = 1
while a[i] do
if a[i] == v then break end
i = i + 1
end
Usually, these are the places where we use these statements, because any other statement following them is unreachable. Sometimes, however, it may be useful to write a return (or a break) in the middle of a block; for instance, if you are debugging a function and want to avoid its execution. In such cases, you can use an explicit do block around the statement:
function foo ()
return --<< SYNTAX ERROR
-- `return' is the last statement in the next block
do return end -- OK
... -- statements not reached
end
In lua 5.2.0-beta-rc1+, you can add a label at the end of your code called ::exit:: or something of the like, and then whenever you need to exit the program just call it like this:
goto exit

Resources