简体   繁体   中英

Ada: Task type as task mark in its own body

I have an Ada task, Do_Something , that needs to "invoke" itself. The way I think of it coming from C++, I have a thread running void Do_Something() and sometimes void Do_Something() needs to spawn more threads that also run void Do_Something() .

Ada (which I'm learning) doesn't like that. This seems to be a M(non)WE:

task body A_Task is

  new_task: access A_Task;
  my_level: Natural;

begin

  accept Do_Something(level: in Natural) do
    my_level := level + 1;
  end Do_Something;

  if my_level < 4 then
    new_task := new A_Task;
    new_task.Do_Something(my_level);
  end if;

end A_Task;

GNAT at least doesn't like this, reporting an error at new_task.Do_Something(my_level); because

task type cannot be used as type mark within its own spec or body

Yet this is easily circumvented by adding a procedure like this outside the task:

procedure Circumvent(level: Natural) is
    new_task: access A_Task;
begin
    new_task := new A_Task;
    new_task.Do_Something(level + 1);
end Circumvent;

then modifying the if statement in A_Task 's body to this:

  if my_level < 4 then
    Circumvent(my_level);
  end if;

This latter version passes GNAT (now we have a M***W***E) and the program runs just fine, even in a non-trivial example I was playing with last night.

This workaround seems so straightforward that I don't understand why the compiler should raise the first error at all! I imagine I must be attacking this problem in completely the wrong way. Is this considered good Ada technique, and if not, what would be the Ada-like way to do this sort of thing?

This behaviour is specified in RM 8.6(17/3) : "If a usage name appears within the declarative region of a type_declaration and denotes that same type_declaration, then it denotes the current instance of the type (rather than the type itself);"

This implies that the actual name of the type cannot be used to instantiate a different object. A wrapper (like yours) would then be one way of doing it. A subtype should also work subtype Foo is A_Task;

Be aware, though, that the C++ way of thinking/doing things is rarely the Ada way of doing things

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM