09-22-2015 07:28 AM
There's any fundamental difference between these two examples or both are "equivalent" ?
09-22-2015 07:37 AM
What does "[Arch]" mean in your subject line?
I don't know what you would say distinguishes whether one is more "robust" than the other.
I would say one main difference is Example A encodes up 3 different states, but there is nothing preventing another state from being queued up in the middle of those if you have another part of your code that is enqueueing states. Meanwhile Example B makes sure all of those will certainly run in order before anything else that gets enqueued is run.
In Example A, handling states between calls, where is that happening? In a different case structure? When does that get handled because the case structure won't run again until something else gets enqueued. Meanwhile if you have some code or subVI right after the case structure that handles errors on exit of the case structure, you should be okay. As long as you handle the error and clear the error wire before it returns to the next loop iteration.
09-22-2015 07:56 AM
I mean "Architecture". Just a convention.
I'm asking that question because i've saw many "variants" of "Message Handling", each one trying to solve that problem of scability and robustness (implying system can get more and more complicated). In Example A, the code between calls is only supposed to handle errors (perhaps passing the state data to handle it directly or enqueue another known state).
Another example is the consumer loop enqueueing itself. Is that recommendable at all? Or it's better launch one Async worker depending on process (DAQ, for example) ?
09-22-2015 08:10 AM
I see no problems with a consumer enqueuing itself. It is to handle an error, I would use "Enqueue at opposite end" so the error handling state gets placed at the front of the queue and is handled right away.
For other things like DAQ or handling communicaiton with another instrument, I tend to make that its own separate loop so that it can be handled regularly to avoid timeout errors and pass any actions based on that data to other loops by way of queues.
09-22-2015 08:40 AM
I have had to privlige (cough cough hack hack) to recieve a QSM developed by a customer that had grown out of control. I came away the impresion that I expressed in this thread where I posted;
"A QSM is the Worm Oroboros of software designs. it is a monster that is best managed by keeping it starved. If allowed to feed itself it will blow up."
I will let you read that thread for more.
A QSM is a natural architecture for a person that comes from the world of programming where they are comfortable with pushing onto and popping off a stacks and see not problem with "Goto" statements. I lean toward Dikstra's opinion that my better-half summarizes as "Goto introduces chaos".
Just my two cents,
Ben
09-22-2015 08:58 AM
@Ben
So, you're suggesting the consumer loop enqueueing itself can bring problems onto future? Actually, it make sense because as system grows, the state dependency will also grows in orders of magnitude.
09-22-2015 09:03 AM
@uChiron wrote:
So, you're suggesting the consumer loop enqueueing itself can bring problems onto future? Actually, it make sense because as system grows, the state dependency will also grows in orders of magnitude.
Agreed.
I feel (my opinion only) that a good design can be documented. A QSM may start out simple but once multiple states are pushing many other states into the queue, it can become impossible to document the state transitions in just 2D so a QSM can "grow inot a monster".
Ben
09-22-2015 10:00 AM
I hate to say a mixture of both can be healthy, but it can. I think of the JKI state machine where you could enqueue multiple cases, or you can enqueue a Macro state that then enqueues multiple states. If you use a macro for a common set of steps it can be very helpful because if I have a macro like Initialize, then any place I might want to go through the reinitialization steps I just add the Macro, and then if I want to change what it does I only have to change it in one place.
But one thing that is to be avoided in the JKI state machine is enqueueing states in states that aren't Macro states. By that I mean I go to a state for Get File Path, and that case enqueues the Load File that then enqueues the Display File. Either make a macro for this and enqueue those cases, or enqueue all three. Having cases add cases can become a nightmare and I think that was part of what Ben was talking about.
Unofficial Forum Rules and Guidelines
Get going with G! - LabVIEW Wiki.
17 Part Blog on Automotive CAN bus. - Hooovahh - LabVIEW Overlord
09-22-2015 11:46 AM
I'll just give my 2c here.
I recently did something like this and I found it very useful to utilise a two-tier command queue on the consumer side if robustness is your goal. Any states which are enqueued from WITHIN the state machine itself go directly to the second queue whereas all commands from outside the State machine go in the first queue (first queue refnum is published, the second one is private). At the beginning of each iteration, I first check if the private Queue has elements in it and I finish them before taking the next item off the public. Both queues are of identical datatype. If required, an additional queue with highest priority could be utilised for stop commands and the like.
This allows for nice debugging of which case executes when with full visibility over when any given external command is finished versus internal macro commands queueing up more states to execute.
I've not seen anyone else doing this but I certainly appreciated it.
09-22-2015 11:56 AM
Shane,
That reads like the scheduling algorithm of an OS where the kernal gets serviced first and then go look for something else to do.
Ben