Joerg Hampel is a guest blogger. As the owner of Hampel Software Engineering and CLA and LabVIEW Champion, his biggest interest lies in team development best practices.
This post was originally published on hampel-soft.com.
Sometimes (actually more often than not), we want our modules to be more than passive libraries. We want them to do more than merely sit there, waiting for work to be thrown at them. Modules shall actively poll for information, acquire data from hardware, manage network connections, and more. We want DQMH Actors!
Caveat: When I say actor, I really mean a DQMH module that executes code by itself, without its’ request events being called. This blog post is not about the Actor Framework.
Now, how can we turn a DQMH module into a DQMH Actor? What could that bringing-to-life of a DQMH module actually look like? Any queued message handler already comes with everything we need to bring it to life, you might say. Still, following the easiest and most straight-forward way might not always take us where we wanted to get in the first place. Let’s take a look at our possibilities.
Self-Messaging
The aforementioned, easy way is to have a message case call itself over and over again, as long as a given condition is met. Take a look at the following screenshot: The Loop Case calls itself, by putting a corresponding message into the message queue, as long as condition == true.
Depending on what you want to achieve, this might be the way to go. Downsides to this approach are (probably amongst others):
- The module still needs to call itself
- There’s a risk of flooding the queue with messages
- Other cases of the MHL might starve
Helper Loops
To avoid clogging the message queue and slowing down the MHL, and to gain additional flexibility, we can move the action into a third, separate loop: The Helper Loop. Here’s an excerpt taken from the DQMH best practices website, explaining this very technique:
When coding a repetitive operation, use a helper loop that is registered to the stop Module event and does the repetitive operation inside the timeout case. Leave the changes to the local data cluster to be handled via the traditional EHL->MHL and then use a Private Request to update the data in the helper loop. This ensures that if the event structure in the helper loop has several events already in the queue, it contains the latest information the next time the timeout is handled.
Helper loops are made up of a while loop containing an event structure. The event structure registers for the Stop Module event of the DQMH module (see the screenshot on the top of this post).
We’ve been using helper loops of two different flavours: Either triggering from within – an event structure timeout case helps with that – or triggered through dynamically registered broadcast events from other modules. Read on to find out more about these two concepts.
Helper loops with timeout event case
The timeout event of an event structure can be used to repetitively execute code. Timings can be controlled by setting the timeout value of the event structure, or by implementing your own timing code within the timeout case of the event structure.
See the update at the bottom of this post for things to look out for when using the timeout event.
The beauty of this solution lies in the ease with which the actor can be enabled or disabled. It’s a question of wiring the timeout value of the event structure to a shift register. Then, you can simply modify the value by the means of DMQH requests.
Setting the timeout value to -1 means that the event structure will never timeout. Your DQMH actor is effectively put to sleep and disabled.
Any other value sets your DQMH actor to be wide awake, waiting for that next timeout to occur!
A timeout value of 0 makes the event structure timeout immediately. You can (and have to) control the timing of the loop manually. Values larger than 0 will make the event structure timeout after this time. If you need precise timing, take into account how long your source code inside the timeout case takes to execute. Also, other events might have been executed in between timeouts.
Helper Loop registered for broadcasts
The second kind of helper loop doesn’t trigger itself. Instead, it registers for other modules’ broadcast events and is then triggered by them. This architecture is even more elegant than the first one. The following screenshots show an exemplary implementation, where the ActorModule DQMH module registers for the System Message broadcast event of the User Interface DQMH module.
Initially, we only supply a constant of the UI.System Message user event refnum for the event registration node. This allows us to create the corresponding event case. Beware that our helper loop is only loaded, but not yet armed.
Update 2018-03-02
It is very important to mention that each event structure that exposes and uses its Dynamic Event Terminals must have its own Event Registration Refnum, created from a separate Register For Events node. Do not fork the Event Registration Refnum wire! For background information, read this blog post.
We can now arm our helper loop (i.e. enable or activate it) by supplying a valid user event refnum for our event registration. In the example, the Obtain Broadcast Events for Registration.vi VI supplies the user event refnum:
Disabling the helper loop in this scenario is as easy as registering for the constant of the UI.SystemMessage event, just as we did during initialisation:
Real-World Example
Where and how do we use this? Well, imagine a simple application that acquires measurement data from some kind of hardware. It needs to display this data, write the data to the hard drive, and stream it via the network to another application.
The DQMH module acquiring data from the hardware (DAQ) would implement the first kind of helper loop. It would use the timeout case of the event structure to read data from the hardware periodically. It would then distribute these blocks of data via a broadcast event.
GUI, LOGGER and STREAMING would be DQMH modules implementing the second flavour of the helper loop. They register for the DAQ module’s broadcast event. Each of them can be enabled and disabled separately. This allows the user to turn logging and streaming on and off independently from displaying the measurement data in the GUI.
How great is that!?
Source Code
In case you’re interested in the example source code, take a look at the gitlab repos at:
https://gitlab.com/hampel-soft/dqmh/hse-application-template
Here’s hoping that this blog post is only half as helpful as these helper loops!
Update 2018-02-12: Timeout Event
When talking to some LabVIEW friends about this blog post, I was confronted with reservations regarding using the timeout event of an event structure for periodic actions.
It is important to state that the timeout event is only triggered if no other events happen during the timespan that was wired to the timeout terminal of the event structure. That’s why it’s called the timeout event after all. So if you’re implementing your event structure to handle all sorts of critical events, your event structure might never actually timeout, and the code inside the timeout event case will never execute.
In our case, the timeout event case IS the critical code, and as we only enable/disable the timeout case and register for the Stop Module event, we should be good [read below for cloneable modules].
I also brought this up on the NI forums, please read Fabiola’s and Darren’s comments.
Update 2019-02-01: Cloneable Modules
Fellow NI Forums user AlexElb pointed out – legitimately – that this article does not explicitly cover the use case of cloneable modules implementing helper loops. As there is a side effect that can cause a lot of headache, I’ll happily elaborate on that.
By design, DQMH creates one set of events for any module, be it singleton or cloneable. As a result, all clones of one cloneable module share the same events. Naturally, you will use the Addressed to This Module.vi
in the helper loop to determine if an Enable or Disable request was sent to a clone.
Depending on how exactly your helper loops work, that could be a problem: Every time you call the Enable or Disable request, all of the clones will leave the “wait for timeout” state and execute the corresponding case, resetting their timeout counter and effectively elongating the timeout period!
If your helper loop’s timing relies on the timeout counter not being interrupted, you have to find a different way of communicating between your MHL and your helper loop (a separate, manually created local event for example).
One thing I want to clarify is that DQMH modules are already Actors, they don’t need to have a helper loop to be considered an actor.
Following Sam Taggart’s definition of an Actor from his presentation “Choosing a Framework”:
“What is an Actor?
Each actor is its own parallel thread
Each actor maintains its own state data
Each actor is autonomous. It has a caller, but it makes its own decisions. Callers can make requests, but ultimately actor is in charge
The only way to communicate with an actor is through messages
Messaging is asynchronous”
In the DQMH Module case, the messages are the events (requests and broadcasts). I believe the DQMH modules follow that description pretty closely.
Fab
I agree completely.
Thanks for chiming in, Fab!
I do understand that the term actor is as much ambiguous as it has a thick history in LabVIEW. Therefor, I had discussed the title of this article with some people before actually posting it, but eventually decided to stick with it, as I expected some educated discussion to be started.
As I wrote, “a DQMH module that executes code by itself, without its’ request events being called” is something else – at least in our way of using DQMH – than a DQMH that merely responds to actions from the outside. Obviously, I have yet to find the correct term for these beasts 🙂
Hi Joerg
You are, I presume, aware that instead of the shift registers you can use a feedback node to set the timeout value for your next loop.
Cheers
Martin
Martin, thanks for your comment. Yes, I’m aware, but I have to admit that for me, shift registers are more easily readable in “a case like this” (<- see what I did there 🙂 ).
Meaning, when we set the timeout of an event case depending on the case that's executed, and we want a dedicated start value, we always go for initialised shift registers.
What's your opinion on this approach?
Joerg,
You can also use an initialized feedback node sending the initializer to the outer loop (right-click on the feedback node).
I would leave the shift register for a template though because there might be more than one case that “wakes up” the helper loop. Also, if you are changing the value to something different than -1 in the “wake-up” case and want to set it back to -1 in the “go to sleep” case then a feedback node doesn’t save that much space. I prefer to use feedback nodes when they are only updated/used in a single case. If the value is going to be modified in multiple cases, I prefer the shift registers because like you said: “they are more readable in that case” 🙂
Fab
Hi Joerg
It definitely makes easier readable code (your’s is very nice btw.) and I would have done exactly the same in this case.
Aesthetically I’m not too keen on having a lot of cases where the wire just goes through.
Fabiola has an excellent point regarding the wake-up/snooze scenario.
So all-in-all. You’re probably right that the shift register approach is the better choice.
Cheers
Martin
Hi Joerg,
The Help-looper is a very good idea.
I have a bit of confuse about the concept.
what’s the different between this Self-Message as you mentioned and the Send Self-Message.vi in Actor Framework?
teddy,
different name, same story:
in AF, Send Self Message is a method of the Actor object which sends a message to the MHL in Actor Core.vi which does not require you to directly touch the actor’s message queue.
Doing the same thing here, requires you to actually place the message in the corresponding queue.
The place in which the message is placed can be determined by Message Priority setting in AF, in DQMH, you just use the approriate Enqueue function.
Hope this helps
Oli
Thank you Oli.
The Helper Loop registered for broadcasts is more like a Observe Pattern,The UI Interface Module can continue to broadcast data(or system message in this demo) to any other modules like Actor Module,and the Actor module can subscribe this data through the Register Event or cancel subscribe through The Unregister Event.
The beauty thing is when the UI Interface Module broadcast system message,it no need know who is the final user.
Am I right?