Hi, -- package spezification package packp6 is procedure tp6pm(N : Long_Integer); end packp6; -- package body with Ada.Text_IO; use Ada.Text_IO; with Ada.Task_Identification; package body packp6 is procedure tp6pm(N : Long_Integer) is use Ada.Task_Identification; package LIO is new Integer_IO(Long_Integer); solution_found : exception; task p6p; task p6m; task body p6p is pp,i : Long_Integer := 0; begin loop i := i+1; pp := 6*i+1; if N mod pp = 0 then new_line;put("pp= ");LIO.put(pp); raise solution_found; end if; end loop; end p6p; task body p6m is pm,i : Long_Integer := 0; begin loop i := i+1; pm := 6*i-1; if N mod pm = 0 then new_line;put("pm= ");LIO.put(pm); raise solution_found; end if; end loop; end p6m; begin null; exception when solution_found => Abort_Task(p6p'Identity); Abort_Task(p6m'Identity); end tp6pm; end packp6; -- test with packp6; use packp6; procedure P6_Test is NN : Long_Integer := 11111111111111111; begin tp6pm(NN); end P6_Test; -- test result: pm= 2071723 pp= 5363222357 When in a task the exception solution_found is raised, then I want all running tasks to be terminated immediately. Apparently this does not happen. How to improve?
On 2020-06-10 14:14, Gilbert Gosseyn wrote: > Hi, It would be easier to understand your post if you started with the explanation and question, rather than throwing a bunch of uncommented code at the reader. > -- package spezification > package packp6 is > procedure tp6pm(N : Long_Integer); > end packp6; > > -- package body > with Ada.Text_IO; use Ada.Text_IO; > with Ada.Task_Identification; > package body packp6 is > procedure tp6pm(N : Long_Integer) is > use Ada.Task_Identification; > package LIO is new Integer_IO(Long_Integer); > solution_found : exception; > > task p6p; > task p6m; > > task body p6p is > pp,i : Long_Integer := 0; > begin > loop > i := i+1; > pp := 6*i+1; > if N mod pp = 0 then > new_line;put("pp= ");LIO.put(pp); > raise solution_found; > end if; > end loop; This is the last point at which you can handle the "raise" above. If there is no handler here, WITHIN task p6p, the exception will try to propagate out of the task, which will terminate the task and STOP the propagation of the exception. > end p6p; > > task body p6m is > pm,i : Long_Integer := 0; > begin > loop > i := i+1; > pm := 6*i-1; > if N mod pm = 0 then > new_line;put("pm= ");LIO.put(pm); > raise solution_found; > end if; > end loop; Same comment as above. > end p6m; > begin > null; > exception > when solution_found => This handler is never entered, because the "null" statement above does not raise solution_found. > Abort_Task(p6p'Identity); > Abort_Task(p6m'Identity); > end tp6pm; > end packp6; [snip] > When in a task the exception solution_found is raised, then I want > all running tasks to be terminated immediately. It is not possible to use an exception, raised in a task, to signal something outside the task in that way. > Apparently this does not happen. How to improve? You must use some other way to inform the main subprogram that a solution has been found. There are may ways, but for example you can use an synchronization object as follows: with Ada.Synchronous_Task_Control; ... solution_found : Ada.Synchronous_Task_Control.Suspension_Object; ... task body p6p ... Ada.Synchronous_Task_Control.Set_True (solution_found); -- Instead of the "raise". ... same for task p6m and in the main subprogram, instead of the null statement and the exception handler: Ada.Synchronous_Task_Control.Suspend_Until_True (solution_found); abort p6p; abort p6m; -- Niklas Holsti niklas holsti tidorum fi . @ .
On 2020-06-10 15:12, Niklas Holsti wrote:
> and in the main subprogram, instead of the null statement and the
> exception handler:
>
> Ada.Synchronous_Task_Control.Suspend_Until_True (solution_found);
> abort p6p;
> abort p6m;
Just an addendum: to make sure that the main subprogram runs, and is not
starved by a child task that is still searching for a solution, you may
want to make the priorities of the child tasks lower than the priority
of the main subprogram (the environment task).
And a further note: generally one should avoid aborting tasks, as that
easily leads to messy race conditions. Better to have the tasks
terminate by themselves. For example, each of the search tasks could now
and then call Ada.Synchronous_Task_Control.Current_State
(solution_found) and terminate itself (exit the loop) if the result is True.
--
Niklas Holsti
niklas holsti tidorum fi
. @ .
On 6/10/20 1:14 PM, Gilbert Gosseyn wrote: > package packp6 is > procedure tp6pm(N : Long_Integer); > end packp6; > > with Ada.Text_IO; use Ada.Text_IO; > package body packp6 is > procedure tp6pm(N : Long_Integer) is > package LIO is new Integer_IO(Long_Integer); Solution_Found : Boolean := False; pragma Atomic (Solution_Found); > > task p6p; > > task body p6p is > pp,i : Long_Integer := 0; > begin > loop exit when Solution_Found; > i := i+1; > pp := 6*i+1; > if N mod pp = 0 then > new_line;put("pp= ");LIO.put(pp); Solution_Found := True; > end if; > end loop; > end p6p; > begin > loop exit when Solution_Found; > i := i+1; > pm := 6*i-1; > if N mod pm = 0 then > new_line;put("pm= ");LIO.put(pm); Solution_Found := True; > end if; > end loop; > end tp6pm; > end packp6; -- Jeff Carter "Unix and C are the ultimate computer viruses." Richard Gabriel 99
On 6/10/20 3:49 PM, Jeffrey R. Carter wrote: > On 6/10/20 1:14 PM, Gilbert Gosseyn wrote: >> package packp6 is >> procedure tp6pm(N : Long_Integer); >> end packp6; >> >> with Ada.Text_IO; use Ada.Text_IO; >> package body packp6 is >> procedure tp6pm(N : Long_Integer) is >> package LIO is new Integer_IO(Long_Integer); > > Solution_Found : Boolean := False; > pragma Atomic (Solution_Found); >> >> task p6p; >> >> task body p6p is >> pp,i : Long_Integer := 0; >> begin >> loop > exit when Solution_Found; > >> i := i+1; >> pp := 6*i+1; >> if N mod pp = 0 then >> new_line;put("pp= ");LIO.put(pp); > Solution_Found := True; >> end if; >> end loop; >> end p6p; Sorry, of course the variables previously in P6m have to be declared here: pm,i : Long_Integer := 0; >> begin >> loop > exit when Solution_Found; > >> i := i+1; >> pm := 6*i-1; >> if N mod pm = 0 then >> new_line;put("pm= ");LIO.put(pm); > Solution_Found := True; >> end if; >> end loop; >> end tp6pm; >> end packp6; -- Jeff Carter "Unix and C are the ultimate computer viruses." Richard Gabriel 99
Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
> you may want to make the priorities of the child tasks lower than the
> priority of the main subprogram (the environment task).
which would normally be System.Default_Priority, unless you've said for
example
procedure Main_Program is
pragma Priority (System.Default_Priority + 1);
is
...
If you are really finished and just want to terminate the program, you can also abort the main task. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr