I'm thinking in terms of, say, doing a long running animation in Fwt. The Docs mention using Actor#sendLater but I can't see this works in a loop situation.
Essentially I want something like:
const class Loopy : Actor {
Bool running := true
override Obj? receive(Obj? o) {
while (running) {
Actor.sleep(Duration(100000000))
... do stuff ...
}
return null
}
}
But being an Actor, when in the loop, it can't receive any control messages (to change running)
I've thought about calling out to a Service, but each Actor has it's own ThreadLocal version of the Service state.
Is this the right way to go about it, or is there a better way?
Cheers.
KevinKelleyFri 24 Feb 2012
In your fan-home, examples/fwt/clock.fan is like that, see if it helps.
Two things: for state variables, use Actor.locals (a map local to the actor where you can stash stuff under a name):
Actor.locals["running"] = true
running := Actor.locals["running"] as Bool
...
Other thing, if you loop inside your receive, you'll block the message queue -- you're supposed to handle the message and get out, so the next message can come thru. So do a sendLater to post the next update.
brianFri 24 Feb 2012
As @qualidafial said, in FWT you can use callLater. In terms of actors...
But being an Actor, when in the loop, it can't receive any control messages (to change running)
Think of Actors as purely object oriented. All state is actually controlled by explicit message passing. So if you want to stop an actor's timer loop, you sent a stop message. Here is a very crude timer loop with stop:
using concurrent
const class Loopy : Actor
{
new make(ActorPool p) : super(p) { sendLater(1sec, "loop") }
Void stop() { send("stop") }
override Obj? receive(Obj? msg)
{
echo("Receive $msg")
if (msg == "stop") Actor.locals["stopped"] = "true"
if (Actor.locals["stopped"] != "true") sendLater(1sec, "loop")
return null
}
static Void main()
{
a := make(ActorPool())
Actor.sleep(10sec)
a.stop
Actor.sleep(5sec)
}
}
SlimerDudeFri 24 Feb 2012
Hi Qualidafial,
Thanks! fwt::Desktop#callLater should work also. As the function would be executed in the same Thread, state would be shared. Though I'm currently thinking the stateful Actor above is probably more idiomatic as it doesn't rely on Fwt.
SlimerDudeFri 24 Feb 2012
Hi Brian, KevinKelley,
Cheers, I get it! You don't sleep in the receive method, instead you sendLater freeing up the Actor to receive stop messages.
SlimerDude Fri 24 Feb 2012
How may I set up a timer loop?
I'm thinking in terms of, say, doing a long running animation in Fwt. The Docs mention using
Actor#sendLater
but I can't see this works in a loop situation.Essentially I want something like:
But being an Actor, when in the loop, it can't receive any control messages (to change
running
)I've thought about calling out to a Service, but each Actor has it's own ThreadLocal version of the Service state.
Feeling lost...
qualidafial Fri 24 Feb 2012
fwt::Desktop#callLater
SlimerDude Fri 24 Feb 2012
Okay, the answer is a little verbose but seems to work...
You have another Actor class that does nothing but hold your shared state:
The initiating method creates the Loop Actor with the above stateful actor:
Both threads can then set / get data on the stateful actor. e.g.
Is this the right way to go about it, or is there a better way?
Cheers.
KevinKelley Fri 24 Feb 2012
In your fan-home,
examples/fwt/clock.fan
is like that, see if it helps.Two things: for state variables, use
Actor.locals
(a map local to the actor where you can stash stuff under a name):Other thing, if you loop inside your
receive
, you'll block the message queue -- you're supposed to handle the message and get out, so the next message can come thru. So do asendLater
to post the next update.brian Fri 24 Feb 2012
As @qualidafial said, in FWT you can use callLater. In terms of actors...
Think of Actors as purely object oriented. All state is actually controlled by explicit message passing. So if you want to stop an actor's timer loop, you sent a stop message. Here is a very crude timer loop with stop:
SlimerDude Fri 24 Feb 2012
Hi Qualidafial,
Thanks! fwt::Desktop#callLater should work also. As the function would be executed in the same Thread, state would be shared. Though I'm currently thinking the stateful Actor above is probably more idiomatic as it doesn't rely on Fwt.
SlimerDude Fri 24 Feb 2012
Hi Brian, KevinKelley,
Cheers, I get it! You don't sleep in the
receive
method, instead yousendLater
freeing up the Actor to receive stop messages.Sweet!