From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Getting-Started Help

Solved!
Go to solution

Update: replaced zip file with current state of project (v2)

Okay, I give up. After 4 hours of trial and error, I've failed to make a functioning egg timer. My goal was to learn how to use AF by creating a simple count-down timer with a separate UI that had to communicate to it asynchronously. At this point, I can't get any messages to execute. Can someone please help me get this thing running and explain where I've gone so horribly wrong? The code is compiled in LV 2011, using AF 2.0.2.

(Yes, I could simply walk over to Stephen's or Allen's desk and ask, but I figure this way the entire community will benefit from my ignorance.)

David Staab, CLA
Staff Systems Engineer
National Instruments
0 Kudos
Message 1 of 10
(8,410 Views)

After a quick glance at your code, it appears that you're using the wrong queue reference to enqueue your messages. If my understanding is correct, the messages you're sending are intended to be sent to the actor core of your timer class hierarchy.  In that case, you'll want to use the 'Receive' queue.  The send queue (which is what you're attempting to use now), is the queue that this actor would use to communicate with another independent actor.

Elijah Kerry
NI Director, Software Community
Message 2 of 10
(5,016 Views)

Also, to be clear, you've only launched one actor.  You do not have asynchronously running actors in your application.  By launching the child actor of the timer, you have the UI funcitonality plus the ability to handle messages and extend the behaviors of the parent. 

My guess is that you actually want a UI and a timer as separate actors which have references to each other's queues, which you would use to send messages between them.  To do this, you'll need to launch these as separate entities.

Elijah Kerry
NI Director, Software Community
Message 3 of 10
(5,016 Views)

ElijahK wrote:

Also, to be clear, you've only launched one actor.  You do not have asynchronously running actors in your application.  By launching the child actor of the timer, you have the UI funcitonality plus the ability to handle messages and extend the behaviors of the parent.

How would they get hold of each other's queues? I don't see an obvious way of sharing that information between them. Do I have to create my own mechanism for publishing an actor's inbound queue?

My guess is that you actually want a UI and a timer as separate actors which have references to each other's queues, which you would use to send messages between them.  To do this, you'll need to launch these as separate entities.

There's also the question of whether the UI should inherit from the core actor, thereby extending its functionality, or whether it should indeed be a separate entity. If this were a real component in the system, I'd be inclined to leave it as-is. But since the point of the exercise was to explore communication between actors, I'll probably make them distinct children of Actor.lvclass.

David Staab, CLA
Staff Systems Engineer
National Instruments
0 Kudos
Message 4 of 10
(5,016 Views)

ElijahK wrote:

After a quick glance at your code, it appears that you're using the wrong queue reference to enqueue your messages. If my understanding is correct, the messages you're sending are intended to be sent to the actor core of your timer class hierarchy.  In that case, you'll want to use the 'Receive' queue.  The send queue (which is what you're attempting to use now), is the queue that this actor would use to communicate with another independent actor.

I'm finding myself really confused by the "relative" nomenclature in the framework. I can never figure out whetere a queue is coming from and going to. Does anyone else have this problem? I think I may rename the various controls and indicators in my copy of the framework with some "absolute" names, like "to-Actor queue" and "from-Messenger queue".

David Staab, CLA
Staff Systems Engineer
National Instruments
0 Kudos
Message 5 of 10
(5,016 Views)

Elijah is right about using the wrong queue, but I see larger problems with your implementation, which I think boil down to assigning responsibilities to the wrong parts of the code.

Here is my understanding of what you are trying to do:  In your Timer:Actor Core, you are trying to send an Update Value message to yourself, (I presume) to update your UI.  This gives you a problem, because the Do for Update Value needs to access attributes of the UI, and they don't exist in a basic Timer.  Also, you've decided to use a DVR to get the value to push to your UI, and you shouldn't have to do that.

Here is what I would do.  First, get rid of the DVR, and put the current value into Timer's attributes.  Write a protected method for Timer to return the current value.  Write a method for Timer to update this value when it is called; this method will take no inputs.  Write a message to invoke this method.  *That* is the message you send from Timer's 250 ms while loop.

Now go to your Timer UI.  Put a reference to the current value indicator into Timer UI's attributes, and write a private accessor to set that reference.  Call the accessor in Timer UI:Actor Core before you invoke the parent node (i.e before you do anything else).  Write an override method for Timer:Update that a) calls the parent, b) calls the proteced current value accessor, and c) sets the control to the new current value via a property node.

That's it; you are done with the part that updates your UI.  When you start up Timer UI:Actor Core, it includes Timer:Actor Core.  Timer:Actor Core will message itself every 250 ms.  That message will invoke the override method for Timer:Update, which updates the time and the UI.

Personally, I would ditch the accessor property nodes in favor of regular VI calls in your messages.  That will force you to keep Actor operations out of your Messages, and might keep things a little more clear for you.

P.S.  I have to check to see which queue I need to access, as well, from time to time, so you aren't alone.  It's not particularly clear how to resolve this going forward, but you have the same problem if you trade queues between two regular state machines, so we've been dealing with this problem for a while.

0 Kudos
Message 6 of 10
(5,016 Views)

niACS wrote:

Here is my understanding of what you are trying to do:  In your Timer:Actor Core, you are trying to send an Update Value message to yourself, (I presume) to update your UI.  This gives you a problem, because the Do for Update Value needs to access attributes of the UI, and they don't exist in a basic Timer.  Also, you've decided to use a DVR to get the value to push to your UI, and you shouldn't have to do that.

Actually, my intention was to get two actors talking to each other, so I'm going to try and pull them back apart instead of making the UI a child of the functional logic. In general, though, the Message:Do methods take in an Actor object so it must be assumed they're going to have to call some method of an actor. When designing a method, what guarantee do you have that it'll only be sent to actors of the right type for whatever methods it calls? It seems that I'll have to design some good error handling into each method to accommodate someone sending it to the wrong type of actor.

Here is what I would do.  First, get rid of the DVR, and put the current value into Timer's attributes.  Write a protected method for Timer to return the current value.  Write a method for Timer to update this value when it is called; this method will take no inputs.  Write a message to invoke this method.  *That* is the message you send from Timer's 250 ms while loop.

Now go to your Timer UI.  Put a reference to the current value indicator into Timer UI's attributes, and write a private accessor to set that reference.  Call the accessor in Timer UI:Actor Core before you invoke the parent node (i.e before you do anything else).  Write an override method for Timer:Update that a) calls the parent, b) calls the proteced current value accessor, and c) sets the control to the new current value via a property node.

Okay, so my little example violates some design guidelines for encapsulation. I can see that. But forcing an actor to access its own attributes through a message seems convoluted. Is that really the way it's normally done, or is that just an artifact of this application? I guess that's the only way for an override of Actor Core.vi to access its own class data, though...

Personally, I would ditch the accessor property nodes in favor of regular VI calls in your messages.  That will force you to keep Actor operations out of your Messages, and might keep things a little more clear for you.

If Actor operations shouldn't be put into Messages, then why does Message:Do.vi take an actor object as an argument?

P.S.  I have to check to see which queue I need to access, as well, from time to time, so you aren't alone.  It's not particularly clear how to resolve this going forward, but you have the same problem if you trade queues between two regular state machines, so we've been dealing with this problem for a while.

With classic implementations (for which I love to use AMC), I normally give each queue the name of its recipient/owner. That gives me an "absolute coordinate" for where the message is going to be sent in the system.

David Staab, CLA
Staff Systems Engineer
National Instruments
0 Kudos
Message 7 of 10
(5,016 Views)

DavidS. wrote:


Actually, my intention was to get two actors talking to each other, so I'm going to try and pull them back apart instead of making the UI a child of the functional logic. In general, though, the Message:Do methods take in an Actor object so it must be assumed they're going to have to call some method of an actor. When designing a method, what guarantee do you have that it'll only be sent to actors of the right type for whatever methods it calls? It seems that I'll have to design some good error handling into each method to accommodate someone sending it to the wrong type of actor.

Right now, there is nothing in the framework to prevent you from sending the wrong message to an actor.  The default behavior is that the actor will throw an error and shut down, which I don't think is a great idea.  We have the same risks with queue-driven state machines, though there you usually just ignore bad messages.

If you choose to pull apart the timer and its UI into unrelated actors (which would not be the normal course of action, btw), you will need to exchange queues between the two actors.  Timer:Update would then pass an update message to Timer UI whenever it was invoked.

Okay, so my little example violates some design guidelines for encapsulation. I can see that. But forcing an actor to access its own attributes through a message seems convoluted. Is that really the way it's normally done, or is that just an artifact of this application? I guess that's the only way for an override of Actor Core.vi to access its own class data, though...

This is most definitely not the way it would be done, and it is overly convoluted *because* you broke encapsulation.  If this were a QDSM, and not AF, your state machine would have the current value as internal data, and your timing loop would not have access to it.  You would pass a message (command + [null] data) from the timing loop into the state machine to trigger an update to the current value.

If Actor operations shouldn't be put into Messages, then why does Message:Do.vi take an actor object as an argument?

I worded that poorly, so let me clarify.  You are currently using accessors to pull data out of the actor, then you do some operation.  (The logical extension of this pattern would be to call an accessor to pass the result back into the actor.)  The operation belongs to the actor, not the message.  Make a single actor method that performs the operation, and then call that method.  Then, down the road, you can make a child actor, override that operation with a child method, and call that new method with the same message.

With classic implementations (for which I love to use AMC), I normally give each queue the name of its recipient/owner. That gives me an "absolute coordinate" for where the message is going to be sent in the system.

Named queues have global scope, which is problematic (see item above about sending the wrong message).  And I don't see how that helps you if you are passing the queue refnums around.  You still have an anonymous wire on your block diagram.  When you actually start exchanging queues between actors, you will hold them in attributes, which you can name as required.  That should help.

On an actor core block diagram, you only have your own receive queue, which is a regular queue refnum, and the send queues of your caller and callees, which have a different wire.  That's another clue.

How do you keep track of the queues you exchange between QDSMs?  Whatever you do should work the same on AF.

I've always used some variant of the command queue that is in the support package for the message maker for my QDSMs.  It's pretty much the same thing, only with variants for the data.

0 Kudos
Message 8 of 10
(5,016 Views)

Thanks for the furthr explanation. After reading through it a few times and poking around in the code, I feel like I'm starting to get the big picture a little better. Let me try to piece together an explanation of how the framework's designed, and you can tell me if I'm wrong. I tried to start with what I know, a QDSM, and translate over to AF:

  • In a software design, I tend to call QDSMs "engines". I can have an IO engine, a UI engine, and an error handling engine in a design; each is implementd as a QDSM. Using this nomenclature, an override of Actor Core.vi is an engine.
  • An actor object is the state of that engine.
  • An actor's other methods are subroutines to be executed in response to requests made of the engine. For example, if an error report is sent to the error handling engine in a system, some subroutine will be executed in response to this. In a QDSM, the subroutine is one or more cases in the main case structure. In AF, it's a series of method calls on the actor object.
  • The base class implementation of Actor Core.vi is the inbound request handler for each engine. It runs asynchronously to the rest of the engine's logic.

Here's a seemingly critical realization I had at one point: Because objects are passed by value on the block diagram, an override of Actor Core.vi -- the engine logic -- doesn't have direct access to its own state data. Accessing and manipulating that data is encapsulated in the request handling logic, which is the base class dispatch of the Actor Core method. Since that method's logic runs asynchronously and on another diagram, there's no way to get to the current state of the actor object.

I threw away my first implementation and tried starting a second one. Here's a screenshot of my Actor Core override to further explain the observation above:second_attempt.png

This seems to be reinforced by the fact that if an actor has a UI, the AF whitepaper recommends providing a reference to the override VI's front panel in the actor's private data, so actor methods can manipulate the UI in response to messages. This is a by-ref workaround for the fact that the Actor Core override is detached from its message handler: the message handler doesn't have access to the override's UI without it.

And vice versa, the override's logic has to send messages to "itself" (really, to its message handler which is a spawn of its parent dispatch) in order to affect its own state. You asserted that this is required in the case of my design because I broke encapsulation, but I cannot find a way to design this timer such that the loop in the screenshot above is able to query the "update period (ms)" parameter without going through a message object to do it.

David Staab, CLA
Staff Systems Engineer
National Instruments
0 Kudos
Message 9 of 10
(5,016 Views)
Solution
Accepted by topic author David S.

Yes, this is pretty much the concept.  You are correct in that you do have to do some work with references to get data to your UI front panel.  It's not so much a workaround as just the way to solve the problem.

The only thing I would clarify relates to your last paragraph.  The framework requires that the actor send a message to itself to get an update; and that's by design, so there is no way around it.  .  The parts that broke encapsulation were 1) using a DVR to move data from the actor's state to the timing loop, just to send the data back to the message handler and 2) having the parent class send a message to itself that requires a child recipient.

But yes, this is pretty much what they are supposed to look like.

0 Kudos
Message 10 of 10
(5,016 Views)