comp.lang.ada
 help / color / mirror / Atom feed
* Running a background task
@ 2008-05-15 20:51 Bender
  2008-05-15 22:31 ` Adam Beneschan
  2008-05-16  0:16 ` Jeffrey R. Carter
  0 siblings, 2 replies; 10+ messages in thread
From: Bender @ 2008-05-15 20:51 UTC (permalink / raw)


Hi, I'm pretty new to Ada, and need to figure out a way to kick off a
background task that runs more or less forever, while normal execution
of the program continues.

Thus far I've figured out how to create a task and start it, but the
procedure calling it requires the task to finish before continuing
on.  I'm sure I just must be using the wrong mechanisms, but I can't
really figure out the answer.

Task definition
---------------------
(spec)
task type Poll_For_Status is
  entry On_String (String : in SideAB)
end Poll_For_Status;

type Task_Access is access Poll_For_Status;
Status_Task : Task_Access;

(body)
  task body Poll_For_Status is
  begin
    accept On_String (String : in SideAB) do
      loop
        delay 3.0
        Send_Status_Req (String);
      end loop;
    end On_String;
  end Poll_For_Status;

Calling procedure
------------------------
procedure Handle_Msg(...) is
  String : SideAB;
  ...
begin
...
  Status_Task := new Poll_For_Status
  Status_Task.On_String (String);
...

If I remove the loop in the task body, it works fine.  Putting it in
seems to halt execution.

Am I missing anything?



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

* Re: Running a background task
  2008-05-15 20:51 Running a background task Bender
@ 2008-05-15 22:31 ` Adam Beneschan
  2008-05-15 23:14   ` Adam Beneschan
  2008-05-16  0:43   ` Bender
  2008-05-16  0:16 ` Jeffrey R. Carter
  1 sibling, 2 replies; 10+ messages in thread
From: Adam Beneschan @ 2008-05-15 22:31 UTC (permalink / raw)


On May 15, 1:51 pm, Bender <Jeffrey.S.Morri...@gmail.com> wrote:
> Hi, I'm pretty new to Ada, and need to figure out a way to kick off a
> background task that runs more or less forever, while normal execution
> of the program continues.
>
> Thus far I've figured out how to create a task and start it, but the
> procedure calling it requires the task to finish before continuing
> on.  I'm sure I just must be using the wrong mechanisms, but I can't
> really figure out the answer.

When Handle_Msg calls on the On_String entry, this starts a
rendezvous, and Handle_Msg stops when the rendezvous is done.  Since
the "accept" has a "do" part, the rendezvous will not be done until
the "do" completes, which in your case never happens.  Thus,
Handle_Msg will never proceed past the entry call.

It's hard for me to give a solution, since I don't know just what
you're trying to accomplish; but you may want to move the loop out of
the "accept".

                                 -- Adam


> Task definition
> ---------------------
> (spec)
> task type Poll_For_Status is
>   entry On_String (String : in SideAB)
> end Poll_For_Status;
>
> type Task_Access is access Poll_For_Status;
> Status_Task : Task_Access;
>
> (body)
>   task body Poll_For_Status is
>   begin
>     accept On_String (String : in SideAB) do
>       loop
>         delay 3.0
>         Send_Status_Req (String);
>       end loop;
>     end On_String;
>   end Poll_For_Status;
>
> Calling procedure
> ------------------------
> procedure Handle_Msg(...) is
>   String : SideAB;
>   ...
> begin
> ...
>   Status_Task := new Poll_For_Status
>   Status_Task.On_String (String);
> ...
>
> If I remove the loop in the task body, it works fine.  Putting it in
> seems to halt execution.
>
> Am I missing anything?




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

* Re: Running a background task
  2008-05-15 22:31 ` Adam Beneschan
@ 2008-05-15 23:14   ` Adam Beneschan
  2008-05-16  0:43   ` Bender
  1 sibling, 0 replies; 10+ messages in thread
From: Adam Beneschan @ 2008-05-15 23:14 UTC (permalink / raw)


On May 15, 3:31 pm, Adam Beneschan <a...@irvine.com> wrote:
> On May 15, 1:51 pm, Bender <Jeffrey.S.Morri...@gmail.com> wrote:
>
> > Hi, I'm pretty new to Ada, and need to figure out a way to kick off a
> > background task that runs more or less forever, while normal execution
> > of the program continues.
>
> > Thus far I've figured out how to create a task and start it, but the
> > procedure calling it requires the task to finish before continuing
> > on.  I'm sure I just must be using the wrong mechanisms, but I can't
> > really figure out the answer.
>
> When Handle_Msg calls on the On_String entry, this starts a
> rendezvous, and Handle_Msg stops when the rendezvous is done.

That should be "Handle_Msg stops until the rendezvous is done".
Sorry.

> Since
> the "accept" has a "do" part, the rendezvous will not be done until
> the "do" completes, which in your case never happens.  Thus,
> Handle_Msg will never proceed past the entry call.

                                 -- Adam



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

* Re: Running a background task
  2008-05-15 20:51 Running a background task Bender
  2008-05-15 22:31 ` Adam Beneschan
@ 2008-05-16  0:16 ` Jeffrey R. Carter
  2008-05-16  0:49   ` Bender
  1 sibling, 1 reply; 10+ messages in thread
From: Jeffrey R. Carter @ 2008-05-16  0:16 UTC (permalink / raw)


Bender wrote:
> Hi, I'm pretty new to Ada, and need to figure out a way to kick off a
> background task that runs more or less forever, while normal execution
> of the program continues.
> 
> Thus far I've figured out how to create a task and start it, but the
> procedure calling it requires the task to finish before continuing
> on.  I'm sure I just must be using the wrong mechanisms, but I can't
> really figure out the answer.
> 
> Task definition
> ---------------------
> (spec)
> task type Poll_For_Status is
>   entry On_String (String : in SideAB)

1. You're missing the terminator semicolon.
2. It's generally not a good idea to reuse the identifier "String", since it 
hides the predefined type String, which will cause confusing error msgs if you 
ever try to use that type.

> end Poll_For_Status;
> 
> type Task_Access is access Poll_For_Status;
> Status_Task : Task_Access;

You have no need for the access type. You can simply say

Status_Task : Poll_For_Status;

Status_Task won't do anything, since it waits for a call to On_String.

You can simplify this even more by saying

task Status_Task is
    entry On_String (...);
end Status_Task;

This assumes that Status_Task is the only instance of Poll_For_Status.

> 
> (body)
>   task body Poll_For_Status is
>   begin
>     accept On_String (String : in SideAB) do
>       loop
>         delay 3.0

Another missing terminator semicolon.

>         Send_Status_Req (String);
>       end loop;

This infinite loop is inside the accept for On_String, which means the task that 
calls On_String will be blocked indefinitely.

>     end On_String;
>   end Poll_For_Status;
> 
> Calling procedure
> ------------------------
> procedure Handle_Msg(...) is
>   String : SideAB;
>   ...
> begin
> ...
>   Status_Task := new Poll_For_Status

As mentioned above, this is unneeded. And it's missing the terminator semicolon.

>   Status_Task.On_String (String);
> ...
> 
> If I remove the loop in the task body, it works fine.  Putting it in
> seems to halt execution.
> 
> Am I missing anything?

My comment on the loop inside the accept is what's confusing you. A rendezvous 
(when a task calls another task's entry) blocks the calling task until it 
completes. Since you have an infinite loop inside the accept, the rendezvous 
never completes and Handle_Msg never returns from the call to On_String.

Possible solutions include

1. Having the task store the value passed to it:

    Side : Sideab;
begin -- Poll_For_Status;
    accept On_String (String : in Sideab) do
       Side := String;
    end On_String;

    loop
       ...

2. Communicating via a protected object rather than a rendezvous. This is a 
bigger change, but depending on your needs might result in a better design.

It may not be important to you, but your loop does not execute every 3 seconds. 
There may be some time after the delay expires before the task starts executing 
again, and using "delay" allows those times to accumulate; there's also the time 
to call the subprogram. If you want it to be as close to every 3 seconds as you 
can get, you should use the "delay until" statement.

-- 
Jeff Carter
"Many times we're given rhymes that are quite unsingable."
Monty Python and the Holy Grail
57



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

* Re: Running a background task
  2008-05-15 22:31 ` Adam Beneschan
  2008-05-15 23:14   ` Adam Beneschan
@ 2008-05-16  0:43   ` Bender
  2008-05-16 15:25     ` Adam Beneschan
  1 sibling, 1 reply; 10+ messages in thread
From: Bender @ 2008-05-16  0:43 UTC (permalink / raw)


On May 15, 4:31 pm, Adam Beneschan <a...@irvine.com> wrote:
> When Handle_Msg calls on the On_String entry, this starts a
> rendezvous, and Handle_Msg stops when the rendezvous is done.  Since
> the "accept" has a "do" part, the rendezvous will not be done until
> the "do" completes, which in your case never happens.  Thus,
> Handle_Msg will never proceed past the entry call.
>
> It's hard for me to give a solution, since I don't know just what
> you're trying to accomplish; but you may want to move the loop out of
> the "accept".
>
>                                  -- Adam

I need to poll the device every 3 seconds.  If I move the loop outside
of the accept, won't it just call Send_Status_Req procedure one time,
then finish the task?

Surely there must be a mechanism similar to C's pthread that allows me
to start a thread and let it worry about itself, while the main thread
continues processing.  All I'm seeing here is that the task is run in
parallel to the other code in the Handle_Msg procedure.  I wan't that
procedure to finish up, and let the rest of the program continue to
run, all with Poll_For_Status running in the background.



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

* Re: Running a background task
  2008-05-16  0:16 ` Jeffrey R. Carter
@ 2008-05-16  0:49   ` Bender
  2008-05-16  4:32     ` Jeffrey R. Carter
  0 siblings, 1 reply; 10+ messages in thread
From: Bender @ 2008-05-16  0:49 UTC (permalink / raw)


On May 15, 6:16 pm, "Jeffrey R. Carter"
<spam.jrcarter....@spam.acm.org> wrote:
> 1. You're missing the terminator semicolon.

Ignore that.  Just remnants of me hastily retyping my code in here.
It all compiles fine.

> 2. It's generally not a good idea to reuse the identifier "String", since it
> hides the predefined type String, which will cause confusing error msgs if you
> ever try to use that type.

Got it.

> You have no need for the access type. You can simply say
>
> Status_Task : Poll_For_Status;
>
> Status_Task won't do anything, since it waits for a call to On_String.
>
> You can simplify this even more by saying
>
> task Status_Task is
>     entry On_String (...);
> end Status_Task;
>
> This assumes that Status_Task is the only instance of Poll_For_Status.

I believe I originally did it this way, but then changed to using the
access stuff because it wasn't behaving the way I wanted it to.  I
thought using the new operator would hold the key to Handle_Msg not
caring about whether the task had finished yet or not, but it didn't.

> This infinite loop is inside the accept for On_String, which means the task that
> calls On_String will be blocked indefinitely.

That's my question in a nutshell.  I need the task to run forever.  I
need the Handle_Msg procedure to end and start handling other incoming
messages.

> 1. Having the task store the value passed to it:
>
>     Side : Sideab;
> begin -- Poll_For_Status;
>     accept On_String (String : in Sideab) do
>        Side := String;
>     end On_String;
>
>     loop
>        ...

Will this solve my problem?  Unfortunately I'm at home at the moment,
but once I get into work I'll give it a shot.  Once the 'end
On_String' is reached, will Handle_Msg continue on, while the task
continues to run?

> 2. Communicating via a protected object rather than a rendezvous. This is a
> bigger change, but depending on your needs might result in a better design.

This is such a simple task that I think what's above should be simple
enough to handle it, but I'll read up on it if necessary.

> It may not be important to you, but your loop does not execute every 3 seconds.
> There may be some time after the delay expires before the task starts executing
> again, and using "delay" allows those times to accumulate; there's also the time
> to call the subprogram. If you want it to be as close to every 3 seconds as you
> can get, you should use the "delay until" statement.

Yeah, I had read something about this before.  I'll look into it.

Thanks for all your help.



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

* Re: Running a background task
  2008-05-16  0:49   ` Bender
@ 2008-05-16  4:32     ` Jeffrey R. Carter
  2008-05-16 14:34       ` Bender
  0 siblings, 1 reply; 10+ messages in thread
From: Jeffrey R. Carter @ 2008-05-16  4:32 UTC (permalink / raw)


Bender wrote:
> 
> That's my question in a nutshell.  I need the task to run forever.  I
> need the Handle_Msg procedure to end and start handling other incoming
> messages.

There are at least 2 tasks in your code: Status_Task and the task that calls 
Handle_Msg. In Ada, all execution is part of a task; a purely sequential program 
(without any explicit tasks) is the execution of an implicit task called the 
environment task.

So "the task" is ambiguous, but I presume you mean Status_Task. As written, 
Status_Task does run forever. It's the other task that's blocked.

> Will this solve my problem?  Unfortunately I'm at home at the moment,
> but once I get into work I'll give it a shot.  Once the 'end
> On_String' is reached, will Handle_Msg continue on, while the task
> continues to run?

Yes, IIUC. When the rendezvous ends, at "end On_String", both tasks continue 
(conceptually) in parallel. Handle_Msg will continue with the next statement 
after the call to Status_Task.On_String, and the Status_Task will continue into 
the loop. I think this is what Beneschan meant by 'move the loop out of the 
"accept"'.

If you have fewer tasks than processors, it's possible to write code such that a 
task that is ready to run never executes ("starvation"), but that's probably not 
something that you need to worry about.

-- 
Jeff Carter
"Many times we're given rhymes that are quite unsingable."
Monty Python and the Holy Grail
57



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

* Re: Running a background task
  2008-05-16  4:32     ` Jeffrey R. Carter
@ 2008-05-16 14:34       ` Bender
  0 siblings, 0 replies; 10+ messages in thread
From: Bender @ 2008-05-16 14:34 UTC (permalink / raw)


On May 15, 10:32 pm, "Jeffrey R. Carter"
<spam.jrcarter....@spam.acm.org> wrote:
> Yes, IIUC. When the rendezvous ends, at "end On_String", both tasks continue
> (conceptually) in parallel. Handle_Msg will continue with the next statement
> after the call to Status_Task.On_String, and the Status_Task will continue into
> the loop. I think this is what Beneschan meant by 'move the loop out of the
> "accept"'.
>
> If you have fewer tasks than processors, it's possible to write code such that a
> task that is ready to run never executes ("starvation"), but that's probably not
> something that you need to worry about.

Just wanted to confirm that moving the loop outside of the accept
block did indeed work the way I needed it to.  Thanks to everyone for
your help.



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

* Re: Running a background task
  2008-05-16  0:43   ` Bender
@ 2008-05-16 15:25     ` Adam Beneschan
  2008-05-16 15:29       ` Adam Beneschan
  0 siblings, 1 reply; 10+ messages in thread
From: Adam Beneschan @ 2008-05-16 15:25 UTC (permalink / raw)


On May 15, 5:43 pm, Bender <Jeffrey.S.Morri...@gmail.com> wrote:
> On May 15, 4:31 pm, Adam Beneschan <a...@irvine.com> wrote:
>
> > When Handle_Msg calls on the On_String entry, this starts a
> > rendezvous, and Handle_Msg stops when the rendezvous is done.  Since
> > the "accept" has a "do" part, the rendezvous will not be done until
> > the "do" completes, which in your case never happens.  Thus,
> > Handle_Msg will never proceed past the entry call.
>
> > It's hard for me to give a solution, since I don't know just what
> > you're trying to accomplish; but you may want to move the loop out of
> > the "accept".
>
> >                                  -- Adam
>
> I need to poll the device every 3 seconds.  If I move the loop outside
> of the accept, won't it just call Send_Status_Req procedure one time,
> then finish the task?

No.  If Send_Status_Req is in a loop, then it will call it in a loop.
This is the same whether or not the loop is inside the accept or
outside of it.  The difference is that if it's inside the accept, it
will hold up the task (which could be the main program, technically
the "environment task") calling the entry being accepted, and if it's
not inside the accept, it won't; but other than that, the behavior
will be the same either way.  I'm not clear on why you'd be confused
about this (i.e. why you think it would call Send_Status_Req only
once)---I suspect you may have some misconception about how tasks
work, but I can't think what it might be, so if this is still
confusing to you, you may need to explain a little more clearly what
you're confused about, so that we can help clear up whatever
misunderstanding you may have.


> Surely there must be a mechanism similar to C's pthread that allows me
> to start a thread and let it worry about itself, while the main thread
> continues processing.

That's pretty much what you're doing with tasks.  Ada, however,
doesn't specify whether tasking is implemented with threads or some
other way---that's up to the implementor.  I think threads is a
popular way to implement tasks, though.


>  All I'm seeing here is that the task is run in
> parallel to the other code in the Handle_Msg procedure.

I'm not clear on what the difference is between this sentence and what
you would *like* to happen.


>  I wan't that
> procedure to finish up, and let the rest of the program continue to
> run, all with Poll_For_Status running in the background.

Did you try moving the loop out of the accept?  If so, what happened?
If it didn't work the way you anticipated, then how did it not work?

                                -- Adam




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

* Re: Running a background task
  2008-05-16 15:25     ` Adam Beneschan
@ 2008-05-16 15:29       ` Adam Beneschan
  0 siblings, 0 replies; 10+ messages in thread
From: Adam Beneschan @ 2008-05-16 15:29 UTC (permalink / raw)


On May 16, 8:25 am, Adam Beneschan <a...@irvine.com> wrote:

> No.  If Send_Status_Req is in a loop, then it will call it in a loop.
> This is the same whether or not the loop is inside the accept or
> outside of it.  The difference is that if it's inside the accept, it
> will hold up the task (which could be the main program, technically
> the "environment task") calling the entry being accepted, and if it's
> not inside the accept, it won't; but other than that, the behavior
> will be the same either way.  I'm not clear on why you'd be confused
> about this (i.e. why you think it would call Send_Status_Req only
> once)---I suspect you may have some misconception about how tasks
> work, but I can't think what it might be, so if this is still
> confusing to you, you may need to explain a little more clearly what
> you're confused about, so that we can help clear up whatever
> misunderstanding you may have.

Please note that I wrote all this before I saw your latest post where
you had gotten things to work.  So it looks like you've gotten
everything figured out now---great!

                                    -- Adam



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

end of thread, other threads:[~2008-05-16 15:29 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-05-15 20:51 Running a background task Bender
2008-05-15 22:31 ` Adam Beneschan
2008-05-15 23:14   ` Adam Beneschan
2008-05-16  0:43   ` Bender
2008-05-16 15:25     ` Adam Beneschan
2008-05-16 15:29       ` Adam Beneschan
2008-05-16  0:16 ` Jeffrey R. Carter
2008-05-16  0:49   ` Bender
2008-05-16  4:32     ` Jeffrey R. Carter
2008-05-16 14:34       ` Bender

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