Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Stopping a running loop inside a nested actor that's running

suppose i have a loop running inside a nested actor. What would be a good mechanism to stop that loop from the caller actor, without stopping the entire nested actor?

0 Kudos
Message 1 of 17
(5,915 Views)

So your nested actor has a helper loop and you want to shut it down from the calling actor?

Ok, passing data/commands to a helper loop is a pretty common implementation. Send a message to the nested actor telling it to shutdown the helper loop. The do for that message should send a stop command to the helper loop. That command could be via user event, notifier, etc.

0 Kudos
Message 2 of 17
(5,037 Views)

Yes i can see how to do that if there is an even structure in the helper loop. Using a notifier or an event structure, would require a time-out wouldn't it? otherwise the loop wouldn't iterate. Is what i'm saying correct? if so, would there be another way?

0 Kudos
Message 3 of 17
(5,037 Views)

Sure, it really depends on what your helper loop is doing and how you want to handle execution timing.

What's wrong with using a notifier with a timeout? Or if you're not a notifier fan switch to a queue. Or use a 0 timeout and handle the case where "Timed Out?" returns true from the notifier or queue (and handle your execution timing with a wait).

0 Kudos
Message 4 of 17
(5,037 Views)

Radical_Raf wrote:

suppose i have a loop running inside a nested actor. What would be a good mechanism to stop that loop from the caller actor, without stopping the entire nested actor?

Don't.

Seriously.

Yes, you can send a message to an actor telling it to stop its helper loop.  I can envision no scenario where a caller should have that much knowledge of how a nested actor does its job.

What use case are you trying to solve with this solution?

I suppose you might write an actor that could stop its helper loop without stopping its message handler.  But that implementation should be completely opaque to the caller.  You don't want a caller that relies on a specific internal implementation, because that creates an unreasonable level of coupling between the caller and nested actors.

Furthermore, why would you want an actor that self-lobotomizes?  If you kill the helper loop, how will you restart it?  (If you can restart it, you haven't killed the helper loop.)

If you need the helper loop to stop, you are much better off killilng the entire actor.  It's perfectly reasonable to have semi-disposable actors in your system, that come and go as needed.

0 Kudos
Message 5 of 17
(5,037 Views)

Except for an event handling loop, I don't think I would use a helper loop at all. It's so much easier to delegate to another actor than to make a custom protocol for interacting with the helper.

Following on niACS's warning, I think you want to tell the nested actor to cancel an action and leave the details of that (e.g. passing a message to a helper loop) to the nested actor.

You'd have something like this:

Three actors: Caller launches Nested launches Helper.

  1. Helper actor has a Action message.
  2. Nested actor has a Begin message, a Done message, a Cancel message, an abstract Report message.
  3. Caller provides Nested an implementation of the Report message.
  4. Caller sends Begin to Nested.
  5. Nested sees Begin and sends Action to Helper.
  6. Helper sees Action and begins performing the action.
  7. Helper processes no more messages until it's done.
  8. At this point Caller and Nested are still responsive, but Helper is busy.
  9. Caller sends Cancel to Nested.
  10. Nested sees Cancel and sets itself to ignore the next Done message.
  11. At this point Caller and Nested are still responsive, and Helper is still busy.
  12. Helper finishes its action and send Done to Nested (which is its caller).
  13. Nested sees Done, and ignores it because the action was cancelled.

That's a sketch of one path. Nested might receive the Done message from Helper before it receives the Cancel message from Caller, and so Caller has to expect it may receive a Report from a cancelled action. Nested could launch and stop Helpers as needed, or just reuse one.

If the goal is to really stop Helper, I think you have to go about it another way. For example, Newport XPS motion controllers allow multiple TCP connections and (at least using their library) you wouldn't directly stop a Helper that had issued a Move command; you would instead use another connection to send a Stop command.

0 Kudos
Message 6 of 17
(5,037 Views)

I really appreciate your collective inputs. Thank you. The use case I was looking at was to have a loop running inside some nested actor which would do a repetitive task, let's say data read from a piece of hardware. I wasn't planning on putting that loop inside the Actor Core.vi override for that nested actor. I was thinking of putting that loop inside some other vi contained in that nested actor's class , and then using that vi's message inside my caller actor actor to start and stop that loop. But now i see the folly of this endeavor - in the future please spare no derision if someone asks  how to do something equally silly... although I'm still learning this so that's my excuse. Come to think of it I may have given you the wrong impression saying that I intended to shut-down the helper loop inside the Actor Core.vi override of a running nested actor. Now what I think i'll do is to have that nested actor read its self enqueuer and send itself the same message recursively to keep doing the same thing, until a message with "stop-state for message" stops it. I will have a case structure inside that nested actor determine the state that this nested actor should be in. All that will be contained in actor vi inside the nested actor, and not in the actor core.vi override. I really appreciate your inputs, and patience.

0 Kudos
Message 7 of 17
(5,037 Views)

auspex wrote:

Except for an event handling loop, I don't think I would use a helper loop at all. It's so much easier to delegate to another actor than to make a custom protocol for interacting with the helper.

We have identified three use cases for helper loops:

1.  The actor needs to receive input from a non-actor space.  User events fall into this category.  Other examples include inteprocess connections (like TCP/IP connections), high-speed data streaming, and certain hardware interactions.

2.  The actor needs to execute a task that takes a very long time relative to the frequency with which it receives messages.  If your actor executes a test sequence, you'll want to offload that task to a helper to keep your actors responsive.

3.  The actor needs to execute a task that requires rigid timing.  Actors are queued message handlers at their core, so you can't guarantee timing without a helper loop of some kind.

0 Kudos
Message 8 of 17
(5,037 Views)

Radical_Raf wrote:

The use case I was looking at was to have a loop running inside some nested actor which would do a repetitive task, let's say data read from a piece of hardware. I wasn't planning on putting that loop inside the Actor Core.vi override for that nested actor. I was thinking of putting that loop inside some other vi contained in that nested actor's class , and then using that vi's message inside my caller actor actor to start and stop that loop.

Now I see why you were asking the question.  You would need to make that loop abort before you could abort the rest of the actor.

Now what I think i'll do is to have that nested actor read its self enqueuer and send itself the same message recursively to keep doing the same thing, until a message with "stop-state for message" stops it.

You can do that, and it's the right answer in some cases.  See, however, my other post from a few minutes ago.  The step you intend to repeat needs to take less time than the frequency with which you expect that actor to recevie messages.  If the step takes 1000 ms, but you'll be sending messages to that actor every 100 ms, you'll build up a backlog of messages, which is a problem.  You'll also want to note that your timing will not be guaranteed.  Any other message that actor can receive has the potential to skew your timing.

When I see the need for a repetitive process like you've described, I assume I am going to eventually hit one of those two concerns sooner or later, and I build a helper loop.

That said, the Time Delay Message is a handy tool for setting up the sort of repetitive messaging you've described.

I will have a case structure inside that nested actor determine the state that this nested actor should be in.

If you think that case structure might grow more than two cases, or you think that you might need a case structure in more than one place, check out the state pattern:  https://en.wikipedia.org/wiki/State_pattern

0 Kudos
Message 9 of 17
(5,037 Views)

All above is good info. Thank you. I actually found one of your earlier posts Implementing the State Pattern in Actor Framework  https://decibel.ni.com/content/message/42468#42468, which if I can understand in time, will be exactly what I need for my application. In the meantime however and to get back to my original idea, I've been fighting with this little problem all afternoon...tgif. So i've attached this zipped file. in there is the project. it's a simple actor project with 2 actors. the nested actor called daq has one method called measure.vi, that has some states in it. the top level actor is supposed to send a message to begin and to stop the measure.vi. there are no loops in the measure.vi. It simply reads its self enqueuer and sends itself a message to go to the next state, and then stay in one particular state, until told otherwise. For some reason however measure.vi never seems to be able to exit out of that one state it is told to stay in, and i just don't know why.

0 Kudos
Message 10 of 17
(5,037 Views)