LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

The main strength of a QMH in State machine applications

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.

  • Try to make processing of any single Message (i.e. "Case" in the Message Handler Loop) very quick, taking very little time.  This allows you to rapidly respond to a new Message when you need to do an "out-of-sequence" response, such as respond to an Error or an Abort condition.
  • 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].
  • One way to keep handling a Message short is to hand the lengthy proccessing to a "Consumer" -- the QMH Case acts like a "Producer" and gets a parallel Consumer loop to do the work, leaving it free to process the next Message.  We do this for some of our Video routines.
  • If your QMH is part of your Top-Level VI, you probably also have an Event Loop.  You can add "QMH-like" ability to an Event Loop by using User Events.  In particular, you can have a single Event that stops the Event Loop (I usually call this User Event "Stop", but then I lack imagination).  This lets the QMH be the "Master" that tells the Event Loop explicitly when to Stop without relying on Local Variables, Global Variables, Local Shared Variables, deliberately creating Errors (like releasing a Queue), or (mis-)using a Value-Signalling Property.

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

0 Kudos
Message 11 of 22
(1,820 Views)

@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.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 12 of 22
(1,802 Views)

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...?

0 Kudos
Message 13 of 22
(1,791 Views)

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

Message 14 of 22
(1,786 Views)
Bob in this particular case I am not quite developing code as ( as you know) I was able to successfully implement a simple state machine since my task does not require paralllel loops / concurrent operations. It was just a simple sequential set of tasks that didn't require parallel Loops. However I was reading up more advanced ways of implementing the same thing and tryIng to see iwhat the QMH offers additionally. So far I have not understood how a QMH can interrupt a running SubVi without the SubVi first completing it's ongoing execution. Have been busy looking into Crossrulz's vi struggling to understand how this stops a SubVi execution mid-way, but with my obvious lack of experience I Still don't understand.

[BADGE NAME]

0 Kudos
Message 15 of 22
(1,777 Views)

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:

  1. Idle (check incoming command)
  2. Start process
  3. Process running
  4. Abort Process
  5. Stop process.

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...

Message 16 of 22
(1,769 Views)

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

Message 17 of 22
(1,763 Views)
Aha! Now I understand 🙂 Thank you Bob and Blokk

[BADGE NAME]

0 Kudos
Message 18 of 22
(1,756 Views)

@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.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 19 of 22
(1,736 Views)

@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.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 20 of 22
(1,732 Views)