Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Auto-stopping dynamically launched nested actors

Second Update: To clarify even more: How do you properly launch dynamic nested actors from a launched root actor such that auto-stop works? I have this working as you would expect in that all nested actors are closed properly when the root actor closed. You can see the first post verifying that. So if you think I am wrong, please provide an explanation or even better a solution that describes a more correct solution. Even with a solution for this problem, I would still like an answer to my previous question.

***********************************************************

First Update: Please do not get caught up into this by-value vs by-reference semantical argument. It is not the focus of my question. My question, as it was originally stated below, is: Why does the Launch Nested Actor.vi not send a message to the caller actor passed in instead of setting a property on the caller actor? From what I can tell, making this change would be more in the spirit of the actor framework (using messages to update an actor's state), make zero difference in the case of non-dynamic launching of actors, and improve the case of dynamic launching of actors.

***********************************************************

I am testing the feasibility of the actor framework for an application. However, I have already arrived at a problem that I know how to workaround but I am not for sure I understand why I need to from a design standpoint of the actor framework.

Problem

You can find my test code attached. In it, I am testing out dynamically launching a nested actor by hitting the start button. When the start button is clicked, Launch Nested Actor.vi is called and the nested actor populates itself in a sub-panel on the front panel of the root actor's Actor Core.vi. Don't worry about such questions of "what happens if you hit the start button twice" because this is a controlled prototype. However, because the mechanism for registering nested actors is by-value only with no messaging, when the stop message is sent to the root actor, it does not know about the dynamically launched nested actor. Thus, the nested actor keeps on happily but irritatingly running with no knowledge that its caller actor has already stopped because nobody called the Stop Core.vi method on it.

Details

To make it clear without looking at my code, I am calling the following code within an event structure that is running parallel to my root actor's Actor Core.vi.

Default.PNG

If you dive into Launch Nested Actor.vi, you will see it updates the Nested Actors property of the Actor.lvlcass via a simple by-value set. So the root actor running in the parllel Actor Core.vi now knows nothing about this launched nested actor, which is why the nested actor isn't auto-stopped when the root actor stops. You can see this in the Actor.lvclass:Stop Core.vi, which iterates through the Nested Actors and sends the stop message for each one. In this case, the Nested Actors property is empty.

A workaround for this is to manually keep track of the dynamically launched nested actor's enqueuer so that you can manually send a stop message. But this defeats the purpose of the auto-stop behavior.

Another workaround is to create a message for the actor to update itself, so that when you launch a nested actor you also send this message. What am I missing? Nothing! Because wait, here I thought I was stupid for missing something regarding the latter method, but after debugging the situation, low and behold, there is a Launch Nested Actor Msg.lvclass message buried in the Actor Framework.lvlib with an associated Actor.lvclass:Send Launch Nested Actor Msg.vi method. It turns out that this method is indeed on the Advanced sub-palette of the Actor Framework palette but this is the default expected behavior in my opinion, not something I should have to debug and hunt for. I looked through the palette at first before diving in, but my thoughts would have been that this was just a subVI already being called.

If you replace the above Launch Nested Actor.vi code with the below code, everything now works as I originally expected!

Expected.PNG

Question

Why isn't this the default, preferred behavior for registering dynamically launched nested actors within the Actor.lvclass? Given the presentation of the auto-stop behavior, I expected this to just work.

This is somewhat of a problem for me, because the actor framework seems built for dynamically launching concurrent processes. However, within my first day of using the framework, I have already spent a good deal of time debugging and understanding this, and so now I'm worried about further hurdles down the line. Actually, now that I think about it, I have built a prototype before using the actor framework on a project that got cancelled. I now remember running into this exact same problem (again right off the bat) and never debugged it (I just manually closed the nested actors if I remember correctly since I was dealing with a prototype that got thrown away).

0 Kudos
Message 1 of 34
(10,336 Views)

Perhaps I'm missing something, but this is what I'm seeing:

-Running your code, root actor front panel appears.

-Click on "Start" button, child actor front panel appears in the sub panel

-Click on "Stop" button of the root actor, everything shuts down properly (no libraries locked).

So it seems to me that stopping the root actor is also stopping the child actor, are you seeing something different?

Craig H. | CLA CTA CLED | Applications Engineer | NI Employee 2012-2023
0 Kudos
Message 2 of 34
(6,078 Views)

Answer:  The default behavior works exactly as you would expect.  You coded your helper loop incorrectly.

The problem is here, in Root's Actor Core.vi:

Untitled.png

Actors are by-value objects.  If you fork the wire, as you have done here, you make a copy of the original actor object; the new copy is not running, and has nothing to do with your instance of the actor (the one with the running Actor Core.)  When you call Launch Nested Actor you will be successful, but the nested actor's enqueuer will be stored in the unlaunched copy, not in the running version where you need it.

Helper loops, like your event structure in this example, are separate from the part of Actor Core that maintains the actor's state.  You really do need to send messages from the helper loop to to yourself, as you have done in your "Enabled" case.

Message 3 of 34
(6,078 Views)

It is because you are running the corrected, non-default code. Within the RootActor:Actor Core.vi, switch the enable structure inside the event structure only to see the default but unexpected behavior.

Edited spelling. Original message typed on a phone. 🙂

0 Kudos
Message 4 of 34
(6,078 Views)

Thanks for the clarification, I didn't notice the disable structure

I guess the high level takeaway is to not call launch nested actor from helper loops.

Craig H. | CLA CTA CLED | Applications Engineer | NI Employee 2012-2023
0 Kudos
Message 5 of 34
(6,078 Views)

Craig_ wrote:

I guess the high level takeaway is to not call launch nested actor from helper loops.

The takeaway is "never copy the actor object". Problems with Launch Nested Actor are only one of the issues you'll run into. Don't fork the actor object to your own loops ... harvest what values you need from it, like its Self Enqueuer, and then pass it along to the Call Parent Node. Don't keep a copy for yourself for any reason.

Message 6 of 34
(6,078 Views)

But that's kind of the point of my post. I only "copied" the actor object up to the parallel while loop with the intention of sending messages to it. The idea was to only use it to send messages. But it's the actor framework itself that broke this! Instead of sending a message to itself, it set a property in the object, which is exactly what you are discouraging.

Is there any reason why the Launch Nested Actor.vi doesn't send a message to the actor it operates on? I can't think of one since that is the intended way to communicate with actors.

0 Kudos
Message 7 of 34
(6,078 Views)

You are badly misunderstanding the concepts of data-flow programming...

You did  "copy the actor object" as you say, but you are interpreting your own words to mean, "I only copied a reference to the actor object" -- you did no such thing.

The copied actor object is a different actor object.  And so it acts differently, since it possesses different data.

0 Kudos
Message 8 of 34
(6,078 Views)

niACS wrote:

Answer:  The default behavior works exactly as you would expect.  You coded your helper loop incorrectly.

Untitled.png

Actors are by-value objects.  If you fork the wire, as you have done here, you make a copy of the original actor object; the new copy is not running, and has nothing to do with your instance of the actor (the one with the running Actor Core.)  When you call Launch Nested Actor you will be successful, but the nested actor's enqueuer will be stored in the unlaunched copy, not in the running version where you need it.

Helper loops, like your event structure in this example, are separate from the part of Actor Core that maintains the actor's state.  You really do need to send messages from the helper loop to to yourself, as you have done in your "Enabled" case.

No offense is intended, but I didn't mark this as correct and disagree. A correct answer will directly address why the Launch Nested Actor.vi is setting a property on the actor object in lieu of sending a message.

This behavior is not what I expect. If it was, I wouldn't have made this post.

I didn't code anything incorrectly, as it is my point that the Launch Nested Actor.vi should be sending a message to the actor it operates on and not simply setting a property on that class. This is the encouraged behavior within the actor framework, so in some sense it is breaking its own rules. It is even mentioned that you can use methods on the class prior to launching the actor and within the actor class itself, and then otherwise, you should be using messaging to communicate with the actor. The Launch Nested Actor.vi breaks this rule, does it not?

Actors are NOT by-value objects. I would agree that actors are normal by-value LabVIEW objects outside of their messaging capability. Given that their messaging framework is the number one way to communicate with them, they are not by-value objects in the strict sense. They can of course become non-by-value again outside of their messaging by further adding reference-based data types to them.

In your picture above, these are not copies of a by-value object (see my picture below from the actor framework template project). Both wires contain the exact same reference to the exact same resource and thus a property of the object is not copied. This is not by-value. The actor is indeed running because what we mean by running in the context of an actor is that its messaging framework, determined by its enqueue reference, is running and listening for messages within the Actor Core.vi

Screen Shot 2015-11-13 at 7.04.30 PM.png

0 Kudos
Message 9 of 34
(6,078 Views)

I perfectly understand dataflow. Please see my other post, but if an object contains a reference, then it is not a true by-value object. When you branch the wire, both wires contain a reference to the same resource. I think it is rather clear from my posts that I in no way intend to act upon the branched wire as if it is a by-reference object with the exception of the messaging reference it contains.

The entire point of this post is that I feel that the Launch Nested Actor.vi is breaking the rule of "only interact with actors through messaging once launched". That is indeed a rule of the actor framework and is broken here unless explained otherwise. I see no reason why it doesn't send a message instead of setting a property on the actor.

People are getting caught up on the branched wire when the exact same thing is done in the actor framework template project. It is not the kernel of this post.

0 Kudos
Message 10 of 34
(6,078 Views)