comp.lang.ada
 help / color / mirror / Atom feed
* How to transfer Class-Wide object to a Task ?
@ 2019-10-14 19:41 William FRANCK
  2019-10-14 19:55 ` Shark8
                   ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-14 19:41 UTC (permalink / raw)


Hey all !
Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO 
dispatching with streams in different tasks ...

Here it is :
I'd like to get from a task RdV (Entry-Access) an object which could be 
any subclass of a root'Class, and pass it to another task

Context : read (Root'Class'Input() ) tagged records from an input 
stream, and send them to anther task which will write 
(Root'Class'Output() ) the given records to another output stream.

I'm stuck with task memory isolation with does NOT allow to pass any 
access object to a Root'Class.

Should I try to use a protected object ?
(not shore this solves the passing of a Class-wide object ...)

Thanks for your feed-back,
William

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 19:41 How to transfer Class-Wide object to a Task ? William FRANCK
@ 2019-10-14 19:55 ` Shark8
  2019-10-14 20:48   ` William FRANCK
  2019-10-14 19:58 ` Dmitry A. Kazakov
  2019-10-14 20:21 ` William FRANCK
  2 siblings, 1 reply; 23+ messages in thread
From: Shark8 @ 2019-10-14 19:55 UTC (permalink / raw)


On Monday, October 14, 2019 at 1:41:55 PM UTC-6, William FRANCK wrote:
> Hey all !
> Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO 
> dispatching with streams in different tasks ...

Generic_Dispatching_Constructor?
https://www.adaic.org/resources/add_content/standards/05rat/html/Rat-2-6.html

Can you give us the actual use-case you're trying to accomplish?

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 19:41 How to transfer Class-Wide object to a Task ? William FRANCK
  2019-10-14 19:55 ` Shark8
@ 2019-10-14 19:58 ` Dmitry A. Kazakov
  2019-10-14 20:58   ` William FRANCK
  2019-10-14 20:21 ` William FRANCK
  2 siblings, 1 reply; 23+ messages in thread
From: Dmitry A. Kazakov @ 2019-10-14 19:58 UTC (permalink / raw)


On 2019-10-14 21:41, William FRANCK wrote:

> Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO 
> dispatching with streams in different tasks ...
> 
> Here it is :
> I'd like to get from a task RdV (Entry-Access) an object which could be 
> any subclass of a root'Class, and pass it to another task
> 
> Context : read (Root'Class'Input() ) tagged records from an input 
> stream, and send them to anther task which will write 
> (Root'Class'Output() ) the given records to another output stream.

Strange design, why not to pipe streams using a FIFO?

> I'm stuck with task memory isolation with does NOT allow to pass any 
> access object to a Root'Class.
> 
> Should I try to use a protected object ?
> (not shore this solves the passing of a Class-wide object ...)

Yes, if using FIFO, a protected object can be used to signal 
non-empty/not-full events at the FIFO ends.

Otherwise, use a reference-counted handle or a plain access type to the 
target object. The reader task allocates the object in the pool and 
passes a handle or access to it to the writer. The writer task writes 
the object and then disposes it.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 19:41 How to transfer Class-Wide object to a Task ? William FRANCK
  2019-10-14 19:55 ` Shark8
  2019-10-14 19:58 ` Dmitry A. Kazakov
@ 2019-10-14 20:21 ` William FRANCK
  2019-10-14 20:32   ` Dmitry A. Kazakov
  2019-10-14 21:57   ` Shark8
  2 siblings, 2 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-14 20:21 UTC (permalink / raw)


On 2019-10-14 19:41:53 +0000, William FRANCK said:

> Hey all !
> Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO 
> dispatching with streams in different tasks ...
> 
> Here it is :
> I'd like to get from a task RdV (Entry-Access) an object which could be 
> any subclass of a root'Class, and pass it to another task
> 
> Context : read (Root'Class'Input() ) tagged records from an input 
> stream, and send them to anther task which will write 
> (Root'Class'Output() ) the given records to another output stream.
> 
> I'm stuck with task memory isolation with does NOT allow to pass any 
> access object to a Root'Class.
> 
> Should I try to use a protected object ?
> (not shore this solves the passing of a Class-wide object ...)
> 
> Thanks for your feed-back,
> William

Here is some code to illustrate
(code needs soem fixings)

with
   Ada.Text_io;

procedure main_ClassWide_to_2Task is

   type Geo2D is tagged record
      Y, X : integer;
      Name : String(1..6) := "Object";
   end record;

   type Circle is new Geo2D with record
      Radius : integer;
   end record;

   myObject : access Geo2D'Class;

   -- ==============================

   task reading is
      entry Object(This : in out Geo2D'Class);
      entry Stop;
   end reading;

   task writing is
      entry Object(This : in Geo2D'Class);
      entry Stop;
   end writing;

   -- ==============================
   task body reading is
      O2D : access Geo2D'Class;
   begin
      loop
         select
            accept Object(This : in out Geo2D'Class);
            declare
               -- (shortcut to simulate real case) ::  Object : 
constant Geo2D'Class := Dispatching_Input (Ada.Tags.Internal_Tag 
(External_Tag), Stream);
            begin
               O2D := new Circle'(0,0,"Cercle",10);
               Ada.Text_io.Put_line("Reading 2D Object: " & O2D.Name); 
-- debug trace
  --             This.all := O2D.all; --Compiler error : "This" is undefined
            end;
         or
            accept Stop;
            exit;
         end select;
      end loop;
   end reading;

   -- ==============================
   task body writing is
      myObject : access Geo2D'Class;
   begin
      loop
         select
            accept Object(This : in Geo2D'Class) do
               myObject := This'Access;
            end Object;
            Ada.Text_io.Put_line("Writing 2D Object: " & This.Name); -- 
debug trace
         or
            accept Stop;
            exit;
         end select;
      end loop;
   end writing;

 -- ==============================
begin
   reading.Object(myObject.all);
   writing.Object(myObject.all);

   reading.Stop;
   writing.Stop;


end main_ClassWide_to_2Task;

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 20:21 ` William FRANCK
@ 2019-10-14 20:32   ` Dmitry A. Kazakov
  2019-10-14 21:04     ` William FRANCK
  2019-10-14 21:57   ` Shark8
  1 sibling, 1 reply; 23+ messages in thread
From: Dmitry A. Kazakov @ 2019-10-14 20:32 UTC (permalink / raw)


On 2019-10-14 22:21, William FRANCK wrote:

> Here is some code to illustrate
> (code needs soem fixings)

The exercise does not make sense. It is a classwork, BTW?

It does not make sense because it could only work if both tasks 
exchanging the object would be in a rendezvous. This would defeat the 
very purpose of doing things in parallel during a rendezvous tasks are 
synchronized.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 19:55 ` Shark8
@ 2019-10-14 20:48   ` William FRANCK
  2019-10-14 22:01     ` Shark8
  0 siblings, 1 reply; 23+ messages in thread
From: William FRANCK @ 2019-10-14 20:48 UTC (permalink / raw)


On 2019-10-14 19:55:22 +0000, Shark8 said:

> On Monday, October 14, 2019 at 1:41:55 PM UTC-6, William FRANCK wrote:
>> Hey all !
>> Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO
>> dispatching with streams in different tasks ...
> 
> Generic_Dispatching_Constructor?
> https://www.adaic.org/resources/add_content/standards/05rat/html/Rat-2-6.html
> 
> Can you give us the actual use-case you're trying to accomplish?

Yes! That's precisly what I'm using to read an existing datafile 
containing records of 10  different structure (and size), then write 
each record back to another stream.

Purpose is to anonymize some of the fields of differently structured records.

Happilly first characters are containing the recordtype name, so I use 
it as External_Tag and can use the OO dispatching of 'Input and 
'Output; selecting the correct 'Read and 'Write.

Allin one program (no multitasking) is OK.
My issue, is that I wanted to gain some speed by having 2 (Ada) tasks : 
one for reading, one for writing.

I did a simple Proof of Concept for the multitasking by transfering an 
IntegerObject. This is OK.

When I replace my Integer by a class-Wide object, I do find the clue to 
make it correct.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 19:58 ` Dmitry A. Kazakov
@ 2019-10-14 20:58   ` William FRANCK
  2019-10-15  4:40     ` Per Sandberg
  2019-10-15  7:21     ` Dmitry A. Kazakov
  0 siblings, 2 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-14 20:58 UTC (permalink / raw)


On 2019-10-14 19:58:34 +0000, Dmitry A. Kazakov said:

> On 2019-10-14 21:41, William FRANCK wrote:
> 
>> Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO 
>> dispatching with streams in different tasks ...
>> 
>> Here it is :
>> I'd like to get from a task RdV (Entry-Access) an object which could be 
>> any subclass of a root'Class, and pass it to another task
>> 
>> Context : read (Root'Class'Input() ) tagged records from an input 
>> stream, and send them to anther task which will write 
>> (Root'Class'Output() ) the given records to another output stream.
> 
> Strange design, why not to pipe streams using a FIFO?
> 
>> I'm stuck with task memory isolation with does NOT allow to pass any 
>> access object to a Root'Class.
>> 
>> Should I try to use a protected object ?
>> (not shore this solves the passing of a Class-wide object ...)
> 
> Yes, if using FIFO, a protected object can be used to signal 
> non-empty/not-full events at the FIFO ends.
> 
> Otherwise, use a reference-counted handle or a plain access type to the 
> target object. The reader task allocates the object in the pool and 
> passes a handle or access to it to the writer. The writer task writes 
> the object and then disposes it.

Thanks you Dimitry for your follow-up.

Here is the multitasking part (simplified) (working, no issue)
for reading the datafile, and writing it back (after some data-process)

My first intention was : while Writing.Bloc is busy writing on the 
output file, Reading.Bloc can take 1 record in advance

Now I have to insert the class-wide object passing in the Bloc.

As You mentionned, should I use a protected type (FIFO)  instead of 2 
// tasks ?

--================
with Ada.Text_io;

procedure main_tasks is

   task reading is
      entry Open;
      entry Bloc;
      entry Stop;
   end reading;

   task  writing is
      entry Create;
      entry Bloc;
      entry Stop;
   end writing;

   task body reading is
   begin
      loop
         select
            accept Open;
               Ada.Text_IO.put_line("Opening file ...");
         or
            accept Bloc do
               Ada.Text_IO.put_line("Reading ...");
            end Bloc;
         or
            accept Stop;
            Ada.Text_IO.put_line("Reading Stopped !");
            exit;
         end select;
      end loop;
   end reading;

   task body writing is
   begin
      loop
      select
         accept Create;
         Ada.Text_IO.put_line("Creating file ...");
         or
            accept Bloc do
               Ada.Text_IO.put_line("Got bloc !");
            end Bloc;
            Ada.Text_IO.put_line("Writing bloc ...");
         or
            accept Stop;
            Ada.Text_IO.put_line("Writing Stopped !");
            exit;
         end select;
      end loop;
   end writing;

begin

   Writing.Create;
   Reading.Open;
   for i in 1..10 loop -- While not end_of_file()
      Reading.Bloc;
      Writing.Bloc;
   end loop;

   Reading.Stop;
   Writing.Stop;

end main_tasks;


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 20:32   ` Dmitry A. Kazakov
@ 2019-10-14 21:04     ` William FRANCK
  0 siblings, 0 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-14 21:04 UTC (permalink / raw)


On 2019-10-14 20:32:45 +0000, Dmitry A. Kazakov said:

> On 2019-10-14 22:21, William FRANCK wrote:
> 
>> Here is some code to illustrate
>> (code needs soem fixings)
> 
> The exercise does not make sense. It is a classwork, BTW?
> 
> It does not make sense because it could only work if both tasks 
> exchanging the object would be in a rendezvous. This would defeat the 
> very purpose of doing things in parallel during a rendezvous tasks are 
> synchronized.

No it's a real use case,
I did wantedto make it simple : one read, then one write. just both in //.
maybe I did the design the wrong way...


Datafile is about 6_000_000 records; 16 GB
Longest record is 1381 Bytes.

William

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 20:21 ` William FRANCK
  2019-10-14 20:32   ` Dmitry A. Kazakov
@ 2019-10-14 21:57   ` Shark8
  2019-10-15  5:43     ` William FRANCK
  1 sibling, 1 reply; 23+ messages in thread
From: Shark8 @ 2019-10-14 21:57 UTC (permalink / raw)


On Monday, October 14, 2019 at 2:21:50 PM UTC-6, William FRANCK wrote:
> On 2019-10-14 19:41:53 +0000, William FRANCK said:
> 
Maybe something like this:

    procedure Example is
        Package Types is
            Subtype Params is Ada.Streams.Root_Stream_Type'Class;
            Type Root   is abstract tagged null record;
            Function Create (Parameters : not null access Params) return Root is abstract;
            
            Type Circle is new Root with record
                Radius : Float;
            end record;
            
            Type Square is new Root with record
                Side : Integer;
            end record;
        Private
            
            Function Create (Parameters : not null access Params) return Square;
            Function Create (Parameters : not null access Params) return Circle;
        End Types;
        
        
        Use Types;
        Package Class_Holder is new Ada.Containers.Indefinite_Holders(Root'Class);
        Task Type Producer( Stream : not null access Ada.Streams.Root_Stream_Type'Class ) is
            Entry Get( Object: out Class_Holder.Holder );
        End Producer;
        
        Task body Producer is
            Function MAKE is new Ada.Tags.Generic_Dispatching_Constructor(
               T           => Types.Root,
               Parameters  => Ada.Streams.Root_Stream_Type'Class,
               Constructor => Types.Create
              );

            Function To_Tag return Ada.Tags.Tag is
            Begin
                Return Square'Tag;
--                  (if    Ch = 'C' then Circle'Tag
--                   elsif Ch = 'S' then Square'Tag
--                   else raise Constraint_Error with "Tag '"&Ch&"' is invalid.");
            End;
            
        Begin
            accept Get (Object : out Class_Holder.Holder) do
                Object:=
                  Class_Holder.To_Holder( MAKE(To_Tag, Stream) );
            end Get;
        end Producer;
        
        Function Get(P : Producer) return Root'Class is
            H : Class_Holder.Holder;
        Begin
            P.Get(H);
            Return H.Element;
        End Get;
        
        
        
        Package Body Types is
            Function Create(Parameters : not null access Params) return Square is
            Begin
                Return (Side => 3);
            End;
            
            Function Create(Parameters : not null access Params) return Circle is
            Begin
                Return (Radius => 2.2);
            End;
        End Types;
        
    begin
        Ada.Text_IO.Put_Line( "START EXAMPLE." );
        declare
            I : Ada.Text_IO.File_Type renames Ada.Text_IO.Standard_Input;
            P : Producer( Ada.Text_IO.Text_Streams.Stream(I) );
            O : Root'Class := Get(P);
        begin
            Ada.Text_IO.Put_Line( "Tag: " & Ada.Tags.Expanded_Name(O'Tag) );
        end;
        Ada.Text_IO.Put_Line( "STOP EXAMPLE." );
    end Example;

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 20:48   ` William FRANCK
@ 2019-10-14 22:01     ` Shark8
  2019-10-15  5:13       ` William FRANCK
  0 siblings, 1 reply; 23+ messages in thread
From: Shark8 @ 2019-10-14 22:01 UTC (permalink / raw)


On Monday, October 14, 2019 at 2:48:33 PM UTC-6, William FRANCK wrote:
> 
> I did a simple Proof of Concept for the multitasking by transfering an 
> IntegerObject. This is OK.
> 
> When I replace my Integer by a class-Wide object, I do find the clue to 
> make it correct.

Ok.
I think it might be due to the Class Read/Write attributes acting different than the Input/Output ones -- I always have to look them up, but one of them reads/writes the discriminants and/or bounds of the item and the other doesn't.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 20:58   ` William FRANCK
@ 2019-10-15  4:40     ` Per Sandberg
  2019-10-15  5:40       ` William FRANCK
  2019-10-16 20:04       ` William FRANCK
  2019-10-15  7:21     ` Dmitry A. Kazakov
  1 sibling, 2 replies; 23+ messages in thread
From: Per Sandberg @ 2019-10-15  4:40 UTC (permalink / raw)


Why not use Ada.Containers.Indefinite_holders to encapsulate the 
Classwide type during store?
----------------
with ADA.Containers.Indefinite_Holders;
package Demo is
    type T1 is interface;
    package T1_Holders is new ADA.Containers.Indefinite_Holders (T1'Class);

    task type Storage_Task is
       entry Internal_Store (D : in T1_Holders.Holder);
       entry Internal_Fetch (D : out T1_Holders.Holder);
    end Storage_Task;

    procedure Store (S : Storage_Task; Var : in Demo.T1'Class );
    Function Fetch(S : Storage_Task) return Demo.T1'Class;
end Demo;
---------------------
package body Demo is
    procedure Store (S : Storage_Task; Var : in Demo.T1'Class ) is
       H : Demo.T1_Holders.Holder;
    begin
       H.Replace_Element (Var);
       S.Internal_Store(H);
    end Store;
    Function Fetch(S : Storage_Task) return Demo.T1'Class is
       H : Demo.T1_Holders.Holder;
    begin
       S.Internal_Fetch (H);
       return H.Element;
    end Fetch;

    task body Storage_Task is
       S : T1_Holders.Holder;
    begin
       loop
          select
             accept Internal_Fetch (D : out T1_Holders.Holder)  do
                D := S;
             end Internal_Fetch;
          or accept Internal_Store (D : in T1_Holders.Holder) do
                S := D;
             end Internal_Store;
          or
             terminate;
          end select;
       end loop;
    end Storage_Task;
end Demo;
---------------------
/P

On 2019-10-14 22:58, William FRANCK wrote:
> On 2019-10-14 19:58:34 +0000, Dmitry A. Kazakov said:
> 
>> On 2019-10-14 21:41, William FRANCK wrote:
>>
>>> Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO 
>>> dispatching with streams in different tasks ...
>>>
>>> Here it is :
>>> I'd like to get from a task RdV (Entry-Access) an object which could 
>>> be any subclass of a root'Class, and pass it to another task
>>>
>>> Context : read (Root'Class'Input() ) tagged records from an input 
>>> stream, and send them to anther task which will write 
>>> (Root'Class'Output() ) the given records to another output stream.
>>
>> Strange design, why not to pipe streams using a FIFO?
>>
>>> I'm stuck with task memory isolation with does NOT allow to pass any 
>>> access object to a Root'Class.
>>>
>>> Should I try to use a protected object ?
>>> (not shore this solves the passing of a Class-wide object ...)
>>
>> Yes, if using FIFO, a protected object can be used to signal 
>> non-empty/not-full events at the FIFO ends.
>>
>> Otherwise, use a reference-counted handle or a plain access type to 
>> the target object. The reader task allocates the object in the pool 
>> and passes a handle or access to it to the writer. The writer task 
>> writes the object and then disposes it.
> 
> Thanks you Dimitry for your follow-up.
> 
> Here is the multitasking part (simplified) (working, no issue)
> for reading the datafile, and writing it back (after some data-process)
> 
> My first intention was : while Writing.Bloc is busy writing on the 
> output file, Reading.Bloc can take 1 record in advance
> 
> Now I have to insert the class-wide object passing in the Bloc.
> 
> As You mentionned, should I use a protected type (FIFO)  instead of 2 // 
> tasks ?
> 
> --================
> with Ada.Text_io;
> 
> procedure main_tasks is
> 
>    task reading is
>       entry Open;
>       entry Bloc;
>       entry Stop;
>    end reading;
> 
>    task  writing is
>       entry Create;
>       entry Bloc;
>       entry Stop;
>    end writing;
> 
>    task body reading is
>    begin
>       loop
>          select
>             accept Open;
>                Ada.Text_IO.put_line("Opening file ...");
>          or
>             accept Bloc do
>                Ada.Text_IO.put_line("Reading ...");
>             end Bloc;
>          or
>             accept Stop;
>             Ada.Text_IO.put_line("Reading Stopped !");
>             exit;
>          end select;
>       end loop;
>    end reading;
> 
>    task body writing is
>    begin
>       loop
>       select
>          accept Create;
>          Ada.Text_IO.put_line("Creating file ...");
>          or
>             accept Bloc do
>                Ada.Text_IO.put_line("Got bloc !");
>             end Bloc;
>             Ada.Text_IO.put_line("Writing bloc ...");
>          or
>             accept Stop;
>             Ada.Text_IO.put_line("Writing Stopped !");
>             exit;
>          end select;
>       end loop;
>    end writing;
> 
> begin
> 
>    Writing.Create;
>    Reading.Open;
>    for i in 1..10 loop -- While not end_of_file()
>       Reading.Bloc;
>       Writing.Bloc;
>    end loop;
> 
>    Reading.Stop;
>    Writing.Stop;
> 
> end main_tasks;
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 22:01     ` Shark8
@ 2019-10-15  5:13       ` William FRANCK
  0 siblings, 0 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-15  5:13 UTC (permalink / raw)


On 2019-10-14 22:01:08 +0000, Shark8 said:

> On Monday, October 14, 2019 at 2:48:33 PM UTC-6, William FRANCK wrote:
>> 
>> I did a simple Proof of Concept for the multitasking by transfering an
>> IntegerObject. This is OK.
>> 
>> When I replace my Integer by a class-Wide object, I do find the clue to
>> make it correct.
> 
> Ok.
> I think it might be due to the Class Read/Write attributes acting 
> different than the Input/Output ones -- I always have to look them up, 
> but one of them reads/writes the discriminants and/or bounds of the 
> item and the other doesn't.

Sorry Shark , my last sentence is not correct  ...
Should read :
'When I replace my Integer by a class-Wide object, I can not find a 
simple way to
make it work.'

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-15  4:40     ` Per Sandberg
@ 2019-10-15  5:40       ` William FRANCK
  2019-10-16 20:04       ` William FRANCK
  1 sibling, 0 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-15  5:40 UTC (permalink / raw)


Thanks Per !

"Containers.Indefinite_holders" seems to be the way to go.
(I didn't used them yet)
I will give it a try :-)

William.

On 2019-10-15 04:40:33 +0000, Per Sandberg said:

> Why not use Ada.Containers.Indefinite_holders to encapsulate the 
> Classwide type during store?
> ----------------
> with ADA.Containers.Indefinite_Holders;
> package Demo is
>     type T1 is interface;
>     package T1_Holders is new ADA.Containers.Indefinite_Holders (T1'Class);
> 
>     task type Storage_Task is
>        entry Internal_Store (D : in T1_Holders.Holder);
>        entry Internal_Fetch (D : out T1_Holders.Holder);
>     end Storage_Task;
> 
>     procedure Store (S : Storage_Task; Var : in Demo.T1'Class );
>     Function Fetch(S : Storage_Task) return Demo.T1'Class;
> end Demo;
> ---------------------
> package body Demo is
>     procedure Store (S : Storage_Task; Var : in Demo.T1'Class ) is
>        H : Demo.T1_Holders.Holder;
>     begin
>        H.Replace_Element (Var);
>        S.Internal_Store(H);
>     end Store;
>     Function Fetch(S : Storage_Task) return Demo.T1'Class is
>        H : Demo.T1_Holders.Holder;
>     begin
>        S.Internal_Fetch (H);
>        return H.Element;
>     end Fetch;
> 
>     task body Storage_Task is
>        S : T1_Holders.Holder;
>     begin
>        loop
>           select
>              accept Internal_Fetch (D : out T1_Holders.Holder)  do
>                 D := S;
>              end Internal_Fetch;
>           or accept Internal_Store (D : in T1_Holders.Holder) do
>                 S := D;
>              end Internal_Store;
>           or
>              terminate;
>           end select;
>        end loop;
>     end Storage_Task;
> end Demo;
> ---------------------
> /P
> 
> On 2019-10-14 22:58, William FRANCK wrote:
>> On 2019-10-14 19:58:34 +0000, Dmitry A. Kazakov said:
>> 
>>> On 2019-10-14 21:41, William FRANCK wrote:
>>> 
>>>> Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO 
>>>> dispatching with streams in different tasks ...
>>>> 
>>>> Here it is :
>>>> I'd like to get from a task RdV (Entry-Access) an object which could be 
>>>> any subclass of a root'Class, and pass it to another task
>>>> 
>>>> Context : read (Root'Class'Input() ) tagged records from an input 
>>>> stream, and send them to anther task which will write 
>>>> (Root'Class'Output() ) the given records to another output stream.
>>> 
>>> Strange design, why not to pipe streams using a FIFO?
>>> 
>>>> I'm stuck with task memory isolation with does NOT allow to pass any 
>>>> access object to a Root'Class.
>>>> 
>>>> Should I try to use a protected object ?
>>>> (not shore this solves the passing of a Class-wide object ...)
>>> 
>>> Yes, if using FIFO, a protected object can be used to signal 
>>> non-empty/not-full events at the FIFO ends.
>>> 
>>> Otherwise, use a reference-counted handle or a plain access type to the 
>>> target object. The reader task allocates the object in the pool and 
>>> passes a handle or access to it to the writer. The writer task writes 
>>> the object and then disposes it.
>> 
>> Thanks you Dimitry for your follow-up.
>> 
>> Here is the multitasking part (simplified) (working, no issue)
>> for reading the datafile, and writing it back (after some data-process)
>> 
>> My first intention was : while Writing.Bloc is busy writing on the 
>> output file, Reading.Bloc can take 1 record in advance
>> 
>> Now I have to insert the class-wide object passing in the Bloc.
>> 
>> As You mentionned, should I use a protected type (FIFO)  instead of 2 
>> // tasks ?
>> 
>> --================
>> with Ada.Text_io;
>> 
>> procedure main_tasks is
>> 
>>   task reading is
>>      entry Open;
>>      entry Bloc;
>>      entry Stop;
>>   end reading;
>> 
>>   task  writing is
>>      entry Create;
>>      entry Bloc;
>>      entry Stop;
>>   end writing;
>> 
>>   task body reading is
>>   begin
>>      loop
>>         select
>>            accept Open;
>>               Ada.Text_IO.put_line("Opening file ...");
>>         or
>>            accept Bloc do
>>               Ada.Text_IO.put_line("Reading ...");
>>            end Bloc;
>>         or
>>            accept Stop;
>>            Ada.Text_IO.put_line("Reading Stopped !");
>>            exit;
>>         end select;
>>      end loop;
>>   end reading;
>> 
>>   task body writing is
>>   begin
>>      loop
>>      select
>>         accept Create;
>>         Ada.Text_IO.put_line("Creating file ...");
>>         or
>>            accept Bloc do
>>               Ada.Text_IO.put_line("Got bloc !");
>>            end Bloc;
>>            Ada.Text_IO.put_line("Writing bloc ...");
>>         or
>>            accept Stop;
>>            Ada.Text_IO.put_line("Writing Stopped !");
>>            exit;
>>         end select;
>>      end loop;
>>   end writing;
>> 
>> begin
>> 
>>   Writing.Create;
>>   Reading.Open;
>>   for i in 1..10 loop -- While not end_of_file()
>>      Reading.Bloc;
>>      Writing.Bloc;
>>   end loop;
>> 
>>   Reading.Stop;
>>   Writing.Stop;
>> 
>> end main_tasks;



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 21:57   ` Shark8
@ 2019-10-15  5:43     ` William FRANCK
  0 siblings, 0 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-15  5:43 UTC (permalink / raw)


Thank you Shark,
I'll give it a try too :-)

And send you all a more complete source code of my use case.

William


On 2019-10-14 21:57:57 +0000, Shark8 said:


> On Monday, October 14, 2019 at 2:21:50 PM UTC-6, William FRANCK wrote:
>> On 2019-10-14 19:41:53 +0000, William FRANCK said:
>> 
> Maybe something like this:
> 
>     procedure Example is
>         Package Types is
>             Subtype Params is Ada.Streams.Root_Stream_Type'Class;
>             Type Root   is abstract tagged null record;
>             Function Create (Parameters : not null access Params) 
> return Root is abstract;
> 
>             Type Circle is new Root with record
>                 Radius : Float;
>             end record;
> 
>             Type Square is new Root with record
>                 Side : Integer;
>             end record;
>         Private
> 
>             Function Create (Parameters : not null access Params) 
> return Square;
>             Function Create (Parameters : not null access Params) 
> return Circle;
>         End Types;
> 
> 
>         Use Types;
>         Package Class_Holder is new 
> Ada.Containers.Indefinite_Holders(Root'Class);
>         Task Type Producer( Stream : not null access 
> Ada.Streams.Root_Stream_Type'Class ) is
>             Entry Get( Object: out Class_Holder.Holder );
>         End Producer;
> 
>         Task body Producer is
>             Function MAKE is new Ada.Tags.Generic_Dispatching_Constructor(
>                T           => Types.Root,
>                Parameters  => Ada.Streams.Root_Stream_Type'Class,
>                Constructor => Types.Create
>               );
> 
>             Function To_Tag return Ada.Tags.Tag is
>             Begin
>                 Return Square'Tag;
> --                  (if    Ch = 'C' then Circle'Tag
> --                   elsif Ch = 'S' then Square'Tag
> --                   else raise Constraint_Error with "Tag '"&Ch&"' is 
> invalid.");
>             End;
> 
>         Begin
>             accept Get (Object : out Class_Holder.Holder) do
>                 Object:=
>                   Class_Holder.To_Holder( MAKE(To_Tag, Stream) );
>             end Get;
>         end Producer;
> 
>         Function Get(P : Producer) return Root'Class is
>             H : Class_Holder.Holder;
>         Begin
>             P.Get(H);
>             Return H.Element;
>         End Get;
> 
> 
> 
>         Package Body Types is
>             Function Create(Parameters : not null access Params) return 
> Square is
>             Begin
>                 Return (Side => 3);
>             End;
> 
>             Function Create(Parameters : not null access Params) return 
> Circle is
>             Begin
>                 Return (Radius => 2.2);
>             End;
>         End Types;
> 
>     begin
>         Ada.Text_IO.Put_Line( "START EXAMPLE." );
>         declare
>             I : Ada.Text_IO.File_Type renames Ada.Text_IO.Standard_Input;
>             P : Producer( Ada.Text_IO.Text_Streams.Stream(I) );
>             O : Root'Class := Get(P);
>         begin
>             Ada.Text_IO.Put_Line( "Tag: " & Ada.Tags.Expanded_Name(O'Tag) );
>         end;
>         Ada.Text_IO.Put_Line( "STOP EXAMPLE." );
>     end Example;


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-14 20:58   ` William FRANCK
  2019-10-15  4:40     ` Per Sandberg
@ 2019-10-15  7:21     ` Dmitry A. Kazakov
  2019-10-15 14:31       ` Optikos
  1 sibling, 1 reply; 23+ messages in thread
From: Dmitry A. Kazakov @ 2019-10-15  7:21 UTC (permalink / raw)


On 2019-10-14 22:58, William FRANCK wrote:

> Here is the multitasking part (simplified) (working, no issue)
> for reading the datafile, and writing it back (after some data-process)
> 
> My first intention was : while Writing.Bloc is busy writing on the 
> output file, Reading.Bloc can take 1 record in advance

That is what OS asynchronous I/O does already. But that is aside.

> Now I have to insert the class-wide object passing in the Bloc.

Stream attributes 'Input and 'Output would do.

> As You mentionned, should I use a protected type (FIFO)  instead of 2 // 
> tasks ?

A protected object to synchronize two tasks:

    Producer -> FIFO -> Consumer
     Block put <- PO -> Block get
     when full          when empty

FIFO does not need interlocking in this scenario. Protected object is 
only to prevent busy waiting at the ends.

Since you are working with streams you can use a storage stream instead 
of raw FIFO:

    Producer -> Storage stream -> Consumer
    Block write when full    Block read when empty

I still do not understand why you serialize and deserialize insted of 
copying bytes as they are.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-15  7:21     ` Dmitry A. Kazakov
@ 2019-10-15 14:31       ` Optikos
  2019-10-15 19:41         ` William FRANCK
  0 siblings, 1 reply; 23+ messages in thread
From: Optikos @ 2019-10-15 14:31 UTC (permalink / raw)


On Tuesday, October 15, 2019 at 2:21:51 AM UTC-5, Dmitry A. Kazakov wrote:
> On 2019-10-14 22:58, William FRANCK wrote:
> 
> > Here is the multitasking part (simplified) (working, no issue)
> > for reading the datafile, and writing it back (after some data-process)
> > 
> > My first intention was : while Writing.Bloc is busy writing on the 
> > output file, Reading.Bloc can take 1 record in advance
> 
> That is what OS asynchronous I/O does already. But that is aside.
> 
> > Now I have to insert the class-wide object passing in the Bloc.
> 
> Stream attributes 'Input and 'Output would do.
> 
> > As You mentionned, should I use a protected type (FIFO)  instead of 2 // 
> > tasks ?
> 
> A protected object to synchronize two tasks:
> 
>     Producer -> FIFO -> Consumer
>      Block put <- PO -> Block get
>      when full          when empty
> 
> FIFO does not need interlocking in this scenario. Protected object is 
> only to prevent busy waiting at the ends.
> 
> Since you are working with streams you can use a storage stream instead 
> of raw FIFO:
> 
>     Producer -> Storage stream -> Consumer
>     Block write when full    Block read when empty
> 
> I still do not understand why you serialize and deserialize insted of 
> copying bytes as they are.

Because OPer is apparently migrating code that was in 2 (UNIXesque) processes to instead be 2 threads in the same process.

William Franck, you really should rework your design to do as Dmitry advises:  FIFO message queues between 2 otherwise asynchronous threads that work on their own slice of the problem (and have their own slice of the problem's data structures).  Under that revised design, only the FIFO's internals need to worry about thread safety, because before posting and after retrieving from the queue the 2 threads run full tilt in their independent territory without interacting with each other.  (This of course assumes that there exists some sort of slicing/partitioning of your problem-space, but there usually is if you look intensely enough for well-defined demarcations.)

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-15 14:31       ` Optikos
@ 2019-10-15 19:41         ` William FRANCK
  2019-10-15 20:03           ` Shark8
  0 siblings, 1 reply; 23+ messages in thread
From: William FRANCK @ 2019-10-15 19:41 UTC (permalink / raw)


Thank you Optikas for your feedback and advice :-)

Sure, the usual design of a multithreaded  'producer' and 'consumer' 
takes advantage of a FIFO round.
I will considering and testing this as Dmitry outlined it for me.

In fact I may considering my design as a FIFO of one (1) (lol) ?

For now I'm implementing the 'Ada.Containers.Indefinite_Holders' in a 
little PoC.
I'l will share this to the group.

As I mentionned, I do use the Stream attributes 'Input and 'Output, and 
is OK in one single program. The challenge for me is to make it work 
(and pass the objects) in a multi-tasking design.

Huh ?!? There is still something to learn about class-wide and 
indefinite type usage :-)


By the way, I really appreciate the support of this group !
Kind regards,
William



On 2019-10-15 14:31:30 +0000, Optikos said:

> On Tuesday, October 15, 2019 at 2:21:51 AM UTC-5, Dmitry A. Kazakov wrote:
>> On 2019-10-14 22:58, William FRANCK wrote:
>> 
>>> Here is the multitasking part (simplified) (working, no issue)
>>> for reading the datafile, and writing it back (after some data-process)
>>> 
>>> My first intention was : while Writing.Bloc is busy writing on the> > 
>>> output file, Reading.Bloc can take 1 record in advance
>> 
>> That is what OS asynchronous I/O does already. But that is aside.
>> 
>>> Now I have to insert the class-wide object passing in the Bloc.
>> 
>> Stream attributes 'Input and 'Output would do.
>> 
>>> As You mentionned, should I use a protected type (FIFO)  instead of 2 
>>> //> > tasks ?
>> 
>> A protected object to synchronize two tasks:
>> 
>> Producer -> FIFO -> Consumer
>> Block put <- PO -> Block get
>> when full          when empty
>> 
>> FIFO does not need interlocking in this scenario. Protected object is> 
>> only to prevent busy waiting at the ends.
>> 
>> Since you are working with streams you can use a storage stream 
>> instead> of raw FIFO:
>> 
>> Producer -> Storage stream -> Consumer
>> Block write when full    Block read when empty
>> 
>> I still do not understand why you serialize and deserialize insted of> 
>> copying bytes as they are.
> 
> Because OPer is apparently migrating code that was in 2 (UNIXesque) 
> processes to instead be 2 threads in the same process.
> 
> William Franck, you really should rework your design to do as Dmitry 
> advises:  FIFO message queues between 2 otherwise asynchronous threads 
> that work on their own slice of the problem (and have their own slice 
> of the problem's data structures).  Under that revised design, only the 
> FIFO's internals need to worry about thread safety, because before 
> posting and after retrieving from the queue the 2 threads run full tilt 
> in their independent territory without interacting with each other.  
> (This of course assumes that there exists some sort of 
> slicing/partitioning of your problem-space, but there usually is if you 
> look intensely enough for well-defined demarcations.)


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-15 19:41         ` William FRANCK
@ 2019-10-15 20:03           ` Shark8
  0 siblings, 0 replies; 23+ messages in thread
From: Shark8 @ 2019-10-15 20:03 UTC (permalink / raw)


One of the nice things about a stream-based design is that (at least theoretically) is that your source is abstracted away -- it doesn't matter if your source is keyboard or radio-receiver or disk or the destination is screen or radio-transmitter or disk.

So, with such a design you could have a system where items are stored in a cache which might be dumped-to/retrieved-from disk, as well as real-time item-generation,  as a 'producer' and where the 'consumer' processes the items.

This sort of design could allow for a high-speed and low-speed channel [to the consumer], as well as a system where [work-]items could be saved -- say for a node restart in certain [distributed] cases.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-15  4:40     ` Per Sandberg
  2019-10-15  5:40       ` William FRANCK
@ 2019-10-16 20:04       ` William FRANCK
  2019-10-16 23:43         ` Anh Vo
  2019-10-17  9:28         ` William FRANCK
  1 sibling, 2 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-16 20:04 UTC (permalink / raw)


Hello Per,

Thaks for the tip !
It saved my life :-).

By using 'Ada.Containers.Indefinite_Holders'
it was possible to transfer the class-wide object from one task-entry 
to another.

If some of you are interested by the 129 SLOC for the sake of sharing designs,
I will post it on this tread.

William.

PS : I didn't found any practical advantage to implement a design with 
a regular FIFO as  the queue will always be at it's max allocation, 
waiting for writing on the file...
Thanks Dmitry for the tip!



On 2019-10-15 04:40:33 +0000, Per Sandberg said:

> Why not use Ada.Containers.Indefinite_holders to encapsulate the 
> Classwide type during store?
> ----------------
> with ADA.Containers.Indefinite_Holders;
> package Demo is
>     type T1 is interface;
>     package T1_Holders is new ADA.Containers.Indefinite_Holders (T1'Class);
> 
>     task type Storage_Task is
>        entry Internal_Store (D : in T1_Holders.Holder);
>        entry Internal_Fetch (D : out T1_Holders.Holder);
>     end Storage_Task;
> 
>     procedure Store (S : Storage_Task; Var : in Demo.T1'Class );
>     Function Fetch(S : Storage_Task) return Demo.T1'Class;
> end Demo;
> ---------------------
> package body Demo is
>     procedure Store (S : Storage_Task; Var : in Demo.T1'Class ) is
>        H : Demo.T1_Holders.Holder;
>     begin
>        H.Replace_Element (Var);
>        S.Internal_Store(H);
>     end Store;
>     Function Fetch(S : Storage_Task) return Demo.T1'Class is
>        H : Demo.T1_Holders.Holder;
>     begin
>        S.Internal_Fetch (H);
>        return H.Element;
>     end Fetch;
> 
>     task body Storage_Task is
>        S : T1_Holders.Holder;
>     begin
>        loop
>           select
>              accept Internal_Fetch (D : out T1_Holders.Holder)  do
>                 D := S;
>              end Internal_Fetch;
>           or accept Internal_Store (D : in T1_Holders.Holder) do
>                 S := D;
>              end Internal_Store;
>           or
>              terminate;
>           end select;
>        end loop;
>     end Storage_Task;
> end Demo;
> ---------------------
> /P
> 
> On 2019-10-14 22:58, William FRANCK wrote:
>> On 2019-10-14 19:58:34 +0000, Dmitry A. Kazakov said:
>> 
>>> On 2019-10-14 21:41, William FRANCK wrote:
>>> 
>>>> Here is a nice issue I have with Ada (GNAT 2012) when trying to do OO 
>>>> dispatching with streams in different tasks ...
>>>> 
>>>> Here it is :
>>>> I'd like to get from a task RdV (Entry-Access) an object which could be 
>>>> any subclass of a root'Class, and pass it to another task
>>>> 
>>>> Context : read (Root'Class'Input() ) tagged records from an input 
>>>> stream, and send them to anther task which will write 
>>>> (Root'Class'Output() ) the given records to another output stream.
>>> 
>>> Strange design, why not to pipe streams using a FIFO?
>>> 
>>>> I'm stuck with task memory isolation with does NOT allow to pass any 
>>>> access object to a Root'Class.
>>>> 
>>>> Should I try to use a protected object ?
>>>> (not shore this solves the passing of a Class-wide object ...)
>>> 
>>> Yes, if using FIFO, a protected object can be used to signal 
>>> non-empty/not-full events at the FIFO ends.
>>> 
>>> Otherwise, use a reference-counted handle or a plain access type to the 
>>> target object. The reader task allocates the object in the pool and 
>>> passes a handle or access to it to the writer. The writer task writes 
>>> the object and then disposes it.
>> 
>> Thanks you Dimitry for your follow-up.
>> 
>> Here is the multitasking part (simplified) (working, no issue)
>> for reading the datafile, and writing it back (after some data-process)
>> 
>> My first intention was : while Writing.Bloc is busy writing on the 
>> output file, Reading.Bloc can take 1 record in advance
>> 
>> Now I have to insert the class-wide object passing in the Bloc.
>> 
>> As You mentionned, should I use a protected type (FIFO)  instead of 2 
>> // tasks ?
>> 
>> --================
>> with Ada.Text_io;
>> 
>> procedure main_tasks is
>> 
>>   task reading is
>>      entry Open;
>>      entry Bloc;
>>      entry Stop;
>>   end reading;
>> 
>>   task  writing is
>>      entry Create;
>>      entry Bloc;
>>      entry Stop;
>>   end writing;
>> 
>>   task body reading is
>>   begin
>>      loop
>>         select
>>            accept Open;
>>               Ada.Text_IO.put_line("Opening file ...");
>>         or
>>            accept Bloc do
>>               Ada.Text_IO.put_line("Reading ...");
>>            end Bloc;
>>         or
>>            accept Stop;
>>            Ada.Text_IO.put_line("Reading Stopped !");
>>            exit;
>>         end select;
>>      end loop;
>>   end reading;
>> 
>>   task body writing is
>>   begin
>>      loop
>>      select
>>         accept Create;
>>         Ada.Text_IO.put_line("Creating file ...");
>>         or
>>            accept Bloc do
>>               Ada.Text_IO.put_line("Got bloc !");
>>            end Bloc;
>>            Ada.Text_IO.put_line("Writing bloc ...");
>>         or
>>            accept Stop;
>>            Ada.Text_IO.put_line("Writing Stopped !");
>>            exit;
>>         end select;
>>      end loop;
>>   end writing;
>> 
>> begin
>> 
>>   Writing.Create;
>>   Reading.Open;
>>   for i in 1..10 loop -- While not end_of_file()
>>      Reading.Bloc;
>>      Writing.Bloc;
>>   end loop;
>> 
>>   Reading.Stop;
>>   Writing.Stop;
>> 
>> end main_tasks;


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-16 20:04       ` William FRANCK
@ 2019-10-16 23:43         ` Anh Vo
  2019-10-17  9:28         ` William FRANCK
  1 sibling, 0 replies; 23+ messages in thread
From: Anh Vo @ 2019-10-16 23:43 UTC (permalink / raw)




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-16 20:04       ` William FRANCK
  2019-10-16 23:43         ` Anh Vo
@ 2019-10-17  9:28         ` William FRANCK
  2019-10-17 10:00           ` Dmitry A. Kazakov
  1 sibling, 1 reply; 23+ messages in thread
From: William FRANCK @ 2019-10-17  9:28 UTC (permalink / raw)


On 2019-10-16 20:04:41 +0000, William FRANCK said:
 I've uploaded my PoC source file on the comp.lang.ada group.

main_ClassWide_to_2Task.adb

"Transfering Class-Wide Objects to task-entries, with 
Ada.Containers.Indefinite_Holders."

-- ==== here it is as a copy =====
with Ada.Containers.Indefinite_Holders,
     Ada.Text_IO;
use
     Ada,
     Ada.Text_IO;

procedure main_ClassWide_to_2Task is
   -- ========================================================================
   -- Demo program showing how to transfer Class-Wide objects to task-entries,
   -- with Ada.Containers.Indefinite_Holders
   -- ========================================================================
   type Geo2D is tagged record
      Y, X : Integer;
      Name : String (1 .. 8) := "Object 0";
   end record;

   type Circle is new Geo2D with record
      Radius : Integer;
   end record;

   package Geo2D_Holders is new Ada.Containers.Indefinite_Holders 
(Geo2D'Class);

   myDataStore : Geo2D_Holders.Holder;

   -- ==========================================================
   package Object_Reading is

      task reading is
         entry Open;
         entry Object (DataStore : in out Geo2D_Holders.Holder);
         entry Stop;
      end reading;
   end Object_Reading;

   -- ==========================================================
   package Object_Writing is

      task writing is
         entry Create;
         entry Object (DataStore : in Geo2D_Holders.Holder);
         entry Stop;
      end writing;
   end Object_Writing;

   -- ==========================================================
   package body Object_Reading is

      task body reading is
         LocalDataStore : Geo2D_Holders.Holder;
         Nb_items       : Natural := 0;  -- for tracing
      begin
         accept Open do -- end go further only after open is complete
            Text_IO.Put_Line (Standard_Error,"Opening file ...");
         end Open;
         Text_IO.Put_Line (Standard_Error,"Input file ready !");
         loop
            select
               accept Object (DataStore : in out Geo2D_Holders.Holder) do
                  DataStore := Geo2D_Holders.Copy (Source => LocalDataStore);
               end Object;
               declare
                  -- (shortcut to simulate real case with Streams and 
*'Class'Input dispatching) ::
                  --Object : constant Geo2D'Class := Dispatching_Input 
(Ada.Tags.Internal_Tag (External_Tag), Stream);
                  O2D : Geo2D'Class := Circle'(0, 0, "Cercle 0", 10); 
-- simulate object creation done by 'Dispatching_Input'
               begin
                  NB_Items := NB_Items +1; -- for demo
                  O2D.Name(7..8) := Natural'Image(Nb_Items); -- for demo
                  Text_IO.Put_Line (Standard_Error,"Reading 2D Object 
#"& Natural'Image(Nb_Items)&": " & O2D.Name); -- debug trace
                  Geo2D_Holders.Replace_Element (Container => 
LocalDataStore, New_Item => O2D);
               end;
            or
               accept Stop do
                  Text_IO.Put_Line (Standard_Error,"Closing Input file...");
               end Stop;
               Text_IO.Put_Line (Standard_Error,"File cloded, Reading 
Stopped !");
               exit;
            end select;
         end loop;
      end reading;

   end Object_Reading;

   -- ==========================================================
   package body Object_Writing is

      task body writing is

         LocalDataStore : Geo2D_Holders.Holder;
         Nb_items  : Natural := 0;

      begin
         accept Create; -- and go ahead (with i.e. opening input file)
         Text_IO.Put_Line (Standard_Error,"Creating file ...");
         Text_IO.Put_Line (Standard_Error,"Output file ready !");
         loop
            select
               accept Object (DataStore : in Geo2D_Holders.Holder) do
                  LocalDataStore := Geo2D_Holders.copy (DataStore );
               end Object; -- go return to the main process, and go 
ahead with reading next record
               if not Geo2D_Holders.Is_Empty(Container => LocalDataStore)
               then
                  declare
                     O2D : Geo2D'Class := Geo2D_Holders.Element 
(Container => LocalDataStore);
                  begin
                     NB_Items := NB_Items +1; -- for demo
                     --  (shortcut to simulate real case with Streams 
and *'Class'Output dispatching) ::
                     Text_IO.Put_Line (Standard_Error,"   Writing 2D 
Object #"& Natural'Image(Nb_Items)&": " & O2D.Name); -- debug trace
                  end;
               end if;
            or
               accept Stop do
                  Text_IO.Put_Line (Standard_Error,"Closing Output file...");
               end Stop;
               Text_IO.Put_Line (Standard_Error,"File Closed, Writing 
Stopped ! ");
               exit;
            end select;
         end loop;
      end writing;
   end Object_Writing;

   -- ==========================================================
   use Object_Reading;
   use Object_Writing;

begin

   Writing.Create;
   Reading.Open;

   for i in 1 .. 9 loop -- While not end_of_file()
      Reading.Object (myDataStore);
      Writing.Object (myDataStore);
   end loop;

   Reading.Stop;
   Writing.Stop;

end main_ClassWide_to_2Task;


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-17  9:28         ` William FRANCK
@ 2019-10-17 10:00           ` Dmitry A. Kazakov
  2019-10-17 10:45             ` William FRANCK
  0 siblings, 1 reply; 23+ messages in thread
From: Dmitry A. Kazakov @ 2019-10-17 10:00 UTC (permalink / raw)


On 2019-10-17 11:28, William FRANCK wrote:
> On 2019-10-16 20:04:41 +0000, William FRANCK said:
> I've uploaded my PoC source file on the comp.lang.ada group.

The code looks wrong. If you use holders it could be like this:

Reader:

    loop
       declare
          read and create a local object
       begin
          accept entry call and in the rendezvous
             copy object into holder passed to the entry
       end;
    end loop;

Writer:

    loop
       call to the reader entry passing local holder
       write the object held by the holder
    end loop;

P.S. Using an access type or reference-counted object would reduce copying.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: How to transfer Class-Wide object to a Task ?
  2019-10-17 10:00           ` Dmitry A. Kazakov
@ 2019-10-17 10:45             ` William FRANCK
  0 siblings, 0 replies; 23+ messages in thread
From: William FRANCK @ 2019-10-17 10:45 UTC (permalink / raw)


Ok, Dmitry, I'll investigate this!

btw, I know you're a senior and respectfull Ada developer :-)

William

On 2019-10-17 10:00:16 +0000, Dmitry A. Kazakov said:

> On 2019-10-17 11:28, William FRANCK wrote:
>> On 2019-10-16 20:04:41 +0000, William FRANCK said:
>> I've uploaded my PoC source file on the comp.lang.ada group.
> 
> The code looks wrong. If you use holders it could be like this:
> 
> Reader:
> 
>     loop
>        declare
>           read and create a local object
>        begin
>           accept entry call and in the rendezvous
>              copy object into holder passed to the entry
>        end;
>     end loop;
> 
> Writer:
> 
>     loop
>        call to the reader entry passing local holder
>        write the object held by the holder
>     end loop;
> 
> P.S. Using an access type or reference-counted object would reduce copying.


^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2019-10-17 10:45 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-14 19:41 How to transfer Class-Wide object to a Task ? William FRANCK
2019-10-14 19:55 ` Shark8
2019-10-14 20:48   ` William FRANCK
2019-10-14 22:01     ` Shark8
2019-10-15  5:13       ` William FRANCK
2019-10-14 19:58 ` Dmitry A. Kazakov
2019-10-14 20:58   ` William FRANCK
2019-10-15  4:40     ` Per Sandberg
2019-10-15  5:40       ` William FRANCK
2019-10-16 20:04       ` William FRANCK
2019-10-16 23:43         ` Anh Vo
2019-10-17  9:28         ` William FRANCK
2019-10-17 10:00           ` Dmitry A. Kazakov
2019-10-17 10:45             ` William FRANCK
2019-10-15  7:21     ` Dmitry A. Kazakov
2019-10-15 14:31       ` Optikos
2019-10-15 19:41         ` William FRANCK
2019-10-15 20:03           ` Shark8
2019-10-14 20:21 ` William FRANCK
2019-10-14 20:32   ` Dmitry A. Kazakov
2019-10-14 21:04     ` William FRANCK
2019-10-14 21:57   ` Shark8
2019-10-15  5:43     ` William FRANCK

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox