05-28-2016 02:19 PM
Hi, BlessedK. Once more, you are asking good questions about reasonably complex topics (for which you are presumably developing code), but are, as in most of your previous posts, refusing to "share" your efforts by posting your code. Instead, you keep asking questions and we keep "guessing" what you are trying to do and making suggestions, which only leads to more questions.
It would not only help us a great deal if you posted your code, it would help other members of the LabVIEW Community who could also learn from our efforts to help you. Please allow others to benefit from our interaction by posting your code.
Here are some of my own ideas about the QMH Design.
Now, you might already have many of these in your code, and my comments might not apply. It would really be nice (and a kindness to the LabVIEW Community that is trying to help you) if you reciprocated by posting your code.
Bob "Broken Record" Schor
05-28-2016 08:19 PM
@Bob_Schor wrote:
- An alternative to a Enqueue at Opposite End (or a "Priority Enqueue") is Flush Queue/Enqueue. If you are going to "Prioritize" ending your QMH or otherwise "breaking" the order of the Messages anyway, discarding the Messages you aren't going to do can accomplish the same thing. [I'd be interested to hear someone more knowledgable than I criticize this idea -- it arose in the context of a structure that didn't permit "Other End" insertions].
Be careful what you ask for...
There is this concept of modularity that you break when you allow another Actior/module/loop/etc clear out your message/state queue. Why should the other loop decide that everything else that is queued up is not needed? Maybe there is something in there that really does need to be done or the entire Earth will be destroyed. But because this other loop flushed the queue, it will never be performed and therefore we are all doomed. Let the module that handles the messages decide when the queue needs flushed so that it can choose to reenqueue important things if necessary and save us from destruction.
So the moral of the story is that if something needs processed ahead of anything else, just use enqueue at opposite end and then let the message handler manage the messages as necessary.
05-29-2016 06:31 AM
Just to jump into the discussion a bit 🙂
In some recent projects I have found that "Dynamic User Events" used as the main communication method between modules greatly simplifies the work. Of course, using Dynamic Events requires a little bit more work to set up (but there are good templates too, like the Delacore QMH) initially. But I find the idea that I can have modules which dynamically subscribe or unsubscribe for messages is very cool. Also, when I generate a user event, so sending a message from a module, ALL other modules which subscribed for this Event Refnum will get it. This does not work with a simple Queue, if you Dequeue an element, you lost it.
Hmm, I am just thinking about disadvantages of user events over Queues right now, please help me out...?
05-29-2016 07:00 AM
I've also used Events as QMH's. One advantage of a Queue is that is easier to access (and thereby manipulate) the "pending events" (though Race Conditions lurk around the corner, as has already been pointed out in this thread). I think it is also easier to "share" a Queue across asynchronous parallel loops -- you don't even have to pass a Queue Reference as long as you are creating an agreed-upon Named Queue.
Bob Schor
05-29-2016 08:29 AM
05-29-2016 09:11 AM - edited 05-29-2016 09:14 AM
So far I have not understood how a QMH can interrupt a running SubVi without the SubVi first completing it's ongoing execution.
In principle it cannot, if you have a subVI with a task inside taking long runtime, and the task is not split up properly...
One possible solution:
Imagine, you have a subVI which has an internal own State Machine with several states, like:
The "Process running" state could have many "sub-states", so for example you can pre-config a special command/process sequence, and insert the multiple "sub-states" into the Queue at once.
Now, we can send a start process command from our UI Handler loop which is located in the MAIN.vi. The subVI's state machine starts to perform the process sequence regarding to the requirements. If you need to abort the actual sequence, you just need to insert an "Abort" msg into the front of the Queue (you can do this either using the ref num of the Queue, or if you named the Queue, you even do not need reference wire).
When the subVI's internal State Machine finishes execution of the actual sub-step, it will "pull" the abort msg from the Queue, and you can do whatever you need to do in the Abort case (release hardware, zero voltage outputs, log abort event, etc...).
What is important to cut up the required sequence/task list into steps so each of the steps do not take too much time to run, so the abort msg does not wait too much before acting.
The above is just a possible example, there are lots of things you need to consider, like data acquisition requirements, required response time, etc...
05-29-2016 09:28 AM
To follow on to Blokk's excellent response about "interrupting" a running sub-VI. Again, the key to being able to do this is to (as I noted) have individual steps in a looping process that take relatively little time. Blokk's suggestion uses a Queued State Machine configured to allow not only the State Machine to send its own "Next State" to the State Machine Queue (analogous to a QMH, except you are enquing States instead of Messages), but to allow the caller to Enque at Opposite End a "High Priority" (such as "Abort") message.
A similar method is to have a Local Shared Variable, Global, or VIG wired to the "Stop" indicator of the sub-VI's loop. [If the sub-VI has no loops, and whatever you are doing inside it has no "abort" mechanism, I think you are stuck]. I've occasionally named such things "Abort" or "Panic Stop" (needless to say, I try not to use them, and am gradually removing them from older code). Note this tends to produce an uncontrolled Abort unless you take additional precautions, but you could now have a single mechanism that would stop all of your loops at once. "With Great Power Comes Great Responsibility".
Bob Schor
05-29-2016 09:36 AM
05-29-2016 08:18 PM
@Bob_Schor wrote:Blokk's suggestion uses a Queued State Machine configured to allow not only the State Machine to send its own "Next State" to the State Machine Queue (analogous to a QMH, except you are enquing States instead of Messages), but to allow the caller to Enque at Opposite End a "High Priority" (such as "Abort") message.
I must warn against this for the modularity argument I made earlier. A state machine handles its states. Nobody else should directly interfer. However, a well designed state machine will listen for messages from outside periodically to see if it should stop, change settings, shutdown, etc.
05-29-2016 08:27 PM
@Blokk wrote:Hmm, I am just thinking about disadvantages of user events over Queues right now, please help me out...?
1. "Priority message". You can't have an event go in front of another event that is already in the queue.
2. Everybody gets the message, even it is not directed to them. Therefore there are a lot of checking "is this message for me? No. That was a waste of a loop iteration..."
There is also the argument of A has to listen for B's event. This creates a dependency of A needing B. With a queue, A just listens on the queue it created for a message from anybody. It is a lot easier to separate the dependence of the two loops with a queue (using a moderator loop is a good way to do this barrier).
With that being said, I tend to use User Events since I have found most of my message handlers need specific data from a lot of sources. It is easier to just register for the user event everywhere that the data is needed.