This post was originally published at Walking the Wires
During the CLA Summit in Rome, I was surprised to see only a handful of hands raised when I asked how many people were familiar with the National Instruments Queued Message Handler project template that ships with LabVIEW 2012 and later. I can understand people not looking at the project templates, thinking they are similar to the old VI templates that have been available in the File > New dialog for many years (Producer Consumer, State Machine, etc.). Unlike the old VI templates, which are more instructional, the newer project templates are intended to be starting points for real-world applications. There are also several sample projects which implement some common applications such as continuous acquisition and logging.
A few architects have created their own project templates, some of which started from the old Producer Consumer template. The NI QMH is a good starting point for many applications, and it addresses a lot of issues that aren’t handled by the Producer Consumer VI template, such as stopping the Event Handling Loop (EHL) from the Message Handling Loop (MHL) via a User Event, simple error handling, etc. Nevertheless, there are a few issues to keep in mind when working with the NI QMH project template:
User Event Registration wrapped inside a subVI – In the NI QMH, the Register For Events function exists in a subVI, as opposed to the same owning diagram as the Event Handling Loop. There are two issues with this approach. First, since the event registration refnum passes through a subVI boundary, the event case that handles the user event gets a non-descriptive name of “User Event”. The other issue is that less-experienced developers might be tempted to fork the registration wire. There should always be a one-to-one ratio between a Register For Events function and an Event Structure. The main issue with using a single event registration refnum for multiple Register For Events functions is that a single event engine gets created, and this can lead to one of the Event structures missing out on events for which it is registered. If you would like to learn more about this and other nuances of User Events, I recommend taking the National Instruments Customer Education course Advanced Architectures in LabVIEW. [Edit] Rumor has it The Register For Events function is no longer wrapped in a subVI in the LabVIEW 2015 version of the NI QMH project template.
The project template creates your own copy of the User Event library as well as the Message Queue library – This means every new project will have a copy of these libraries. This can be confusing for inexperienced developers, and they might make modifications to one of these libraries in a given QMH project and forget about the modifications when they go start a new QMH project. In addition, all the VIs end up having the same nice icons, making it hard to spot at a glance that these VIs might have been modified. This also means that if there are improvements made to the NI QMH project template, you will have to go back to your existing projects and make the modifications yourself. This is not necessarily a bad thing, but it is something to keep in mind. If you have to support an existing project, do not assume that the original developers left the User Event and Message Queue libraries unchanged.
Priority enqueueing (enqueueing at the front of the queue) – This feature is very useful to ensure that the Exit message gets ahead of any other messages in the message queue. However, I have often seen developers make several messages high priority. When there are multiple potential high priority messages, there is no guarantee that the Exit message will stay at the front of the message queue. An added measure to take if you are using LabVIEW 2014 or later is to make firing the Stop User Event high priority.
Using the QMH as a State Machine – Advanced LabVIEW developers and architects have moved away from using the QMH because of bad experiences trying to use it as a state machine. The main issue is trying to enqueue a series of messages that need to be executed back to back without interruption (except for the Exit message). One suggested way around this is to enqueue multiple messages using a For Loop. The NI QMH accomplishes this by providing an “enqueue multiple messages” polymorphic instance of the enqueue VI. However, there is still a slight possibility that a message could get enqueued by a parallel process between two loop iterations within this VI. My suggestion is to use a state machine subVI that is also registered to listen to the stop event. This state machine can be implemented with the Simple State Machine project template with the Event structure in the idle case. Another option is to have the cases of the state machine in the timeout event of the Event structure.
At this point, someone usually asks “Why not implement the QMH as a single loop, just like the JKI State Machine?”. This would make sure that new states are not enqueued until a series of states are executed. This is definitely a good option, and it has the added benefit of keeping all the local data in the loop’s shift register. It also makes it easier to add data from the event cases. However, the dequeuer needs a timeout that sends the state machine to the “Idle” case to service events, and the Event structure ends up having a timeout as well to ensure no enqueues are missed. This turns the state machine loop into a polling for events/messages machine. In the NI QMH, there is no need for timeouts in the Event structure or in the dequeuer. If there is no interaction from the user with the front panel, then the whole VI is simply dormant until an event from the front panel causes it to wake up.
Wrapping Up – If you want to learn more about the NI QMH project template and figure out how you can use it (or not), click Create Project from the Getting Started Window in LabVIEW and then click on the “More Information” link within the QMH project template description. You can also just create your first project based on this template, which will include a copy of the documentation. Finally, be sure to check out the presentation called Queued Message Handler: Caveats and Design Decisions.
We will be sharing our own QMH project template in the near future. We call it the Delacor QMH or DQMH. The main modifications we have done are to address the issue with the event registration and use User Events as our inter-process communication mechanism. We got some of these ideas from Justin Goeres’ 2011 presentation on Private/Public User events. We also decided to wrap the message queue in a class, and make it private to the DQMH module just like I presented at the 2013 European CLA Summit in Paris. But alas, I am getting ahead of myself. Stay tuned to find out more later this year.
Happy wiring,
Fab
Re: “First, since the event registration refnum passes through a subVI boundary, the event case that handles the user event gets a non-descriptive name of “User Event”.”
You can give the User Event a descriptive name, though it is rather non-obvious. Create a constant of your User Event, change its label to what you want to eventually see in the Event structure, wire the constant into the Register function, and create an indicator from that. Then delete the constant and wire up your original User Event. The indicator, used as your subVI output terminal, retains the name.
James,
Great tip!
Another option is to use the coerce to type function as described here: http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Officially-Support-quot-Coerce-to-Type-quot/idi-p/1213153
Thanks,
Fab
Quote : “Using the QMH as a State Machine – …. The NI QMH accomplishes this by providing an “enqueue multiple messages” polymorphic instance of the enqueue VI. However, there is still a slight possibility that a message could get enqueued by a parallel process between two loop iterations within this VI.”
I’m wondering how could the states enqueue in parallel as the “Enqueue Message (Array).vi” a non-reentrant and for loop is also not configured for parallelism.
Ajayvignesh,
It is a very small window of opportunity, yes, the enqueue message (array).vi might not be reentrant, but it is not the only VI that has access to put messages in the queue, we also have the enqueue message (single message). So, there is a small possibility of having a single message be enqueued while the enqueue message (array) is in between iterations. It is a very small possibility, however it is still possible. The worst part is that this would be very hard to reproduce, so you might see it from time to time and not know why/how is happening. That is why if you can not afford a sequence of messages to be interrupted to make them an atomic action in a single case in your Message Handling Loop. I hope this makes sense.
You could actually build an “atomic enqueue multiple” subVI. It would send the messages in a single batch and the dequeuing subVI would pass them out one-by-one.
Yes that makes sense 🙂 Awaiting for Delacore QMH.
We have announced the Delacor QMH in this blog post.
Hope you like it!
Fab
Hello, and thanks for the great blog!
Quote: “Rumor has it that the Register For Events function will no longer be wrapped in a subVI in future versions of the NI QMH project template. We will update this blog post as soon as this rumor is confirmed.”
It seems that in LabVIEW 2015 the Register For Events function is not in the subVI anymore.
Iikka
Hi there,
Thanks for the feedback, we greatly appreciate it and for giving us a bump on this one, you’re absolutely correct. NI did indeed make this change to the QMH template.
Chris
And we edited the post to reflect the change.
Thanks,
Fab