Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

I have taken the OOP Plunge...but have a couple of questions

Solved!
Go to solution

ToddLesher wrote:

Part of what's confusing me is that the Using AF pdf says the child class of a Report type message has a Do.vi that is invoked by the callee actor. But in the Offline Demo, the Feedback Cooler callee doesn't use the abstract class method. Perhaps if the messages were grouped by actors in that demo, I could see the correlation better - perhaps not, though

I downloaded the Fan demo and was looking through the source code and... I see why you're confused.  It confuses me too.  There are some differences between this implementation and what I was trying to describe above.  I think this answers your question.  (And if I'm really lucky it'll even be correct.)

Let's focus on four classes, FeedbackCooler (actor class), FanSystem (actor class), ErrorReportMessage (message class), and ReportErrorToCooler (message class.)  Here are some relationships to keep in mind:

Message Relationships

-ReportErrorToCooler is an input message for the FeedbackCooler.

-ErrorReportMessage is an output message for the FanSystem.

-ReportErrorToCooler is a child of ErrorReportMessage.

Actor Relationships

-The FeedbackCooler actor manages the FanSystem actor.  It is responsible for configuring the FanSystem object, launching the actor, and shutting it down when it's time to exit.  I'll call FeedbackCooler the "master" actor and FanSystem the "slave" actor.  (I have to think too much when reading "callee" and "caller.")

-The FeedbackCooler class is statically dependent on the FanSystem class.

-The FanSystem class is not statically dependent on the FeedbackCooler class.

When you say "the Feedback Cooler callee," I'm interpreting that as the FanSystem actor.  (Caller = master, callee = slave.)  As I (poorly) described above, in order to allow FanSystem to send messages to FeedbackCooler without it being statically dependent on FeedbackCooler, there are two things that need to take place:

1. You need to have some way to inject the correct FeedbackCooler message object (ReportErrorToCooler) into the FanSystem object at run time.

This requirement is satisfied in the FeedbackCooler.ActorCore method. This implementation injects the correct message object before launching the actor at the setter method circled in red.  My description above (and the pdf) describe a way to allow the message object to be injected after launching the actor. This implementation is a little easier to understand. 

FeedbackCooler.ActorCore.PNG

This is the fp and bd for the FanSystem setter method. Note it uses the ErrorReportMessage--the parent message associated with that class--as the input terminal, but the developers have connected ReportErrorToCooler--the child class--to that terminal on the FeedbackCooler block diagram.

FanSystem.WriteErrorReportMessage.PNG

2. You need to invoke the ErrorReportMessage.Send method somewhere in the FanSystem source code.

This requirement is satisfied in the FanSystem.SwitchToSecondaryFan method.  You can see where the previously injected ReportErrorToCooler object is unbundled (red arrow) and sent to the class input terminal of the ErrorReportMessage.Send.

FanSystem.SwitchToSecondaryFan.PNG

The FanSystem doesn't use an abstract method because this design doesn't need an abstract method.  If I recall correctly previous versions of the AF included the message queue within the message object.  In that design it might be necessary to override the Send method, depending on the implementation details.

I don't know if that helps at all or just muddies the waters more.  It's way past the stupid hour and my brain is a bit mushy right now.

Message 11 of 28
(1,907 Views)

This absolutely makes sense, thank you.

I'm having trouble understanding something about making reusable code. Both master/caller and slave/callee are statically linked to the ErrorReportMessage class:

FanSystem.SwitchToSecondaryFan calls the (parent class) method ErrorReportMessage.SendErrorReport (as highlighted in the last picture above)

The Cooler's ReportErrorToCooler.Do method calls the parent class method ErrorReportMessage.ReadReportedError

If I wanted to use this FanSystem in another project (without a cooler), ErrorReportMessage would have to be included, somehow. I was getting hung up on the fact that the Cooler was not able to provide it's own message that the Fan would call. Is it just as simple as including a FanOutputMessages.lvlib alongside the Fan library?

0 Kudos
Message 12 of 28
(1,907 Views)

Right, if FanSystem called a Cooler message directly we'd be unable to reuse FanSystem without dragging along the Cooler message classes.

Creating FanOutputMessages.lvlib is one option, but it's not what I'd do.  I prefer to keep all input and output messages in the same library as the actor.  The exception is if the message is generic enough to be used by many different actors, in which case I'll include it as part of the famework library or I'll create a "reuse candidate" extension library for the framework.  (I've done both with LapDog.)

0 Kudos
Message 13 of 28
(1,907 Views)

Oops. Right, I see the dependency chain, now. Thanks again.

0 Kudos
Message 14 of 28
(1,907 Views)

Quick question about communication (tcp/ip). Although I've implemented this countless times with "regular" LabVIEW programming, I am not sure the best way to do it with the actor framework. I probably don't want my listener in the loop that processes messages because while it's listening it can't process any other incoming messages. I thought about having a parallel loop which listens, then passes the connection refnum to the processing loop, which would manage everything. But, if I do that, then I need to either 1) continuously send messages telling that loop to do a "tcp read" or 2) just put a timeout on the queue and at timeout do a read. #2 doesn't seem like a bad idea, but I am not sure if there is a better way.

I have a feeling a similar situation may come up with the DAQ thread, because I wan't to be continuously measuring which would require continuously queueing up messages telling the actor to read. I know there is an example of the DAQ stuff in angry eagles, but it doesn't seem very reusable, because you would have to strip out all the DAQ code if you were using a task other than voltage.

0 Kudos
Message 15 of 28
(1,907 Views)

I'm not that familiar with tcp/ip so I can't give you any concrete answers, just general ideas...

"...then I need to either 1) continuously send mesages telling that loop to do a "tcp read" or 2) just put a timeout on the queue and at timeout do a read. #2 doesn't seem like a bad idea, but I am not sure if there is a better way."

In general I try to avoid putting any critical code in a queue timeout handler--there's always the chance the timeout won't get a chance to execute.  In fact, I prefer not to use timeouts at all.  If "tcp read" is in a timeout handler, it's much harder to figure out how often it is going to execute.  I have to track down eveything that sends messages to the receiver, find out how frequently they send messages, and figure out the worst case scenario for the length of time between queue timeouts.  It can get very tricky, very quickly, and sometimes I can't guarantee the queue will ever timeout.

When I need a loop to execute an action at regular intervals I create a "timer" loop. It is essentially a loop whose sole purpose is to send a specific message to a specific loop at specific intervals. They are quick to write and it's easy to reason about what is happening. (The loop receives a "tcp read" message every 20 ms.)  One of the AF examples (could be the Cooler...?) has a Timer actor that I believe does exactly that.

0 Kudos
Message 16 of 28
(1,907 Views)

Ok, your suggestion is pretty much like my #1.  Just wasn't sure if that's the best way to do it, but it sounds like it is. And I agree with the timeout stuff; this is exactly why I never understand the use of timeouts on an event structure to do things. If the user has a lot of front panel activity, way too much time may pass before certain things happen.

0 Kudos
Message 17 of 28
(1,907 Views)

for(imstuck) wrote:

Quick question about communication (tcp/ip). Although I've implemented this countless times with "regular" LabVIEW programming, I am not sure the best way to do it with the actor framework.

Do it with Actors.  One actor for the listener.  One for the connection (or two, one for each end).  Your other actors should do tcp communication by launching clones of these tcp actors.

0 Kudos
Message 18 of 28
(1,907 Views)


drjdpowell wrote:

for(imstuck) wrote:

Quick question about communication (tcp/ip). Although I've implemented this countless times with "regular" LabVIEW programming, I am not sure the best way to do it with the actor framework.

Do it with Actors.  One actor for the listener.  One for the connection (or two, one for each end).  Your other actors should do tcp communication by launching clones of these tcp actors.

Thanks, this had crossed my mind, but I didn't know if three threads was overkill for managing a network connection. I will implement it this way and see how it goes.

0 Kudos
Message 19 of 28
(1,907 Views)

"Threads" are cheap in LabVIEW.   Actors are mostly just a relatively small VI waiting on a queue, which takes minimal resources.  It was only when I tried out the Desktop Execution Trace kit that I really started to appreciate that. 

Note also that you only have to make your three actors once, then endlessly reuse clones of them for TCP communication everywhere.  I have my own system of Actors (not Actor Framework) and I wrote three actors to do my TCP communication.  I made a post about it here

0 Kudos
Message 20 of 28
(1,907 Views)