07-30-2012 02:15 AM
I do the continous execution in a different way. I guess it is the same way that you find ugly, however I find it very similar to the parallel loop solution.
So I create one method in my actor class that is equal to one iteration of the loop (If we would make a parallel loop). I make one message that usually has no message data, because my Iteration method also has no input (If you feel like you can have inputs to it). This message executes this iteration method in it's Do.vi.
I send this "iteration" message as the last step of my Iteration method. If you want to handle stop conditions, you can decide with a case to send the "iteration" message or the Stop message.
It has the following advantages:
- You have access to all the private datas of the Actor, so handling state changes - what you wanted to do - becomes easier.
- A Stop message coming from another actor also stops the actor easily.
- No possibility of an un-stoppable loop (if one iteration is finished in foreseeable time), as the main actor can always send a Stop message.
Disadvantages:
- you have to send one empty message. I really don't know how much, but it's obvious that it's at least a bit overhead, because LabVIEW has to handle the message handling. (One LabVIEW expert could comment on this.)
- not so easy to see the loop, however you can get used to it.
- To test you obviously need an actor based test environment. However if you do it for some time, you will find pattens and templates that are reusable.
07-30-2012 09:03 AM
all I've seen is that you could do it by having the process enqueue itself to the actor, but this seems really ugly to me (similar to Daklu's aversion to the QSM which enqueues to itself).
Consider your process which has three proposed states: Idle, Read Position, and Control on Position. What is the aversion to sending these messages to self? It is no different than a simple QDSM Queue and Enum loop...
Once the process is moved to a parallel loop in the Actor Core.vi override, things like handling and syncronizing data become more difficult. There are a few cases that require a parallel loop (Timed Loop, Reading Buffered Data, ...). What are you gaining by creating the parallel loop?
Another big design decision is based upon how the "continuous process" needs to share and obtain its data (position). There are many considerations:
07-30-2012 09:03 AM
Why use a SEQ instead of a DVR? When I want to send an object to a parallel loop I create a different class that has as its private data a DVR that wraps the original object.
07-30-2012 03:17 PM
I want control to continue a time-critical sense. I can't afford to have the actual control broken up by whatever requests the actor is receiving from its caller.
07-30-2012 03:54 PM
Isn't one of the intended uses of the "Time-Delayed Send Message" VI to schedule future updates of continuous processes within an Actor?
-- James
BTW> a related post by Daklu on LAVA about how he handles continuous processes with his actor-like system.
07-30-2012 06:31 PM
They achieve the same result for basic use, so his choice of API is really pretty irrelevant. But here are some reasons not to use a DVR for all situations:
07-30-2012 06:37 PM
"Time-critical" execution usually just means designing your process to execute within a certain window every time. It requires the ability to schedule threads and guarantee there are no lock-outs or waits in the critical path. It doesn't really mean that you have to write something that can't be interrupted though, and unless you're throwing together a quick-n-dirty concept program, you're 90% likely to need to be able to interrupt the code with a message so you can stop it or change its behavior.
Anyway, even LVRT's Timed Loops handle time-critical code by simply reporting whether the previous iteration completed in the allowed window. It's your responsibility to handle the situation when it doesn't. I would design my time-critical code in the same manner, checking iteration [i-1]'s elapsed time and making decisions for iteration based on the result.
07-30-2012 06:58 PM
LVB wrote:
What is the aversion to sending these messages to self? It is no different than a simple QDSM Queue and Enum loop...
Ayup... and therein lies the problem.
In principle there is nothing wrong with having a loop send a message to itself. In practice, based on the code I have seen over the years, it is very easy to introduce subtle race conditions that may not be apparent or discovered until it's too late. QSMs often use "states" where sub vis are more appropriate. That's what makes them dangerous. The "states" must execute in a specific order. If the expected sequence is disrupted unpredictable things happen. Usually that's bad. Sending messages to self makes it easy to introduce unintentional sequential requirements that can't be enforced.
If you don't allow the loop to send messages to itself, you can't queue up a bunch of operations to perform. You're forced to create atomic message handlers and sub vis. A properly written message handling loop can receive any message at any time and react in a predictable and known way. As long as your messages are atomic and there are no message sequence expectations in the receiving loop, you can safely send messages to self. Unfortunately, the idea of atomic messages isn't widely known in the LV community, so often when I encounter self-sent messages there is also an unintended message sequence requirement in the receiving loop.
07-30-2012 07:17 PM
GotRobotFriends wrote:
I want control to continue a time-critical sense. I can't afford to have the actual control broken up by whatever requests the actor is receiving from its caller.
The link James posted shows two techniques I've employed. I use a metronome (called a "heartbeat" in the post) when I need to execute some process at periodic intervals. If the process has to be more or less continuous, I separate the message handling loop from the continuous loop and share data between them. (The "DVR" option in the post.)
Note that my DVR option doesn't have a message handler. I have found it easier in the long run to restrict each loop to a single mechansim for getting data from outside sources. For the Image Rendering loop in the DVR option, that mechanism is the DVR.
07-30-2012 08:10 PM
Then I especially recommend creating a parallel loop within a child actor core.