11-04-2015 09:34 AM
When designing anything other than a quick proof of concept application, I try to stick to the QMH. Normally, there are four loops: One with an event structure for handling UI input, one main control loop for distributing messages & data, one for hardware control and one for programmatic UI updates. For ease of explanation, let's assume these loops are numbered in the order in which they were presented above (event structure loop = 1, main control = 2, H/W control = 3, UI update = 4).
Every user action first goes through loop 1 and is then passed to loop 2. From there it is distributed to 3 and/or 4. There are some instances where a user action goes 1-2-4 with nothing really happening at 2 except passing the data straight to 4. While I am tempted to send the data straight to 4 from 1, my gut's telling me to stick to the design pattern and always distribute through the main control loop. I guess the ultimate goal of this would be code readablity--a dependable data flow paradigm.
I'd like to know your thoughts on the issue. Would you pass straight the data straight to loop 4?
11-04-2015 10:14 AM - edited 11-04-2015 10:18 AM
I would pass the data straight to 4. You're wasting CPU cycles dequeuing/re-enqueuing the data and adding complexity by having a case that doesn't really 'do' anything.
In applications like this (similar scale/complexity), I tend to create all of my queues during the application initialisation, bundle them together into a type-def and then pass that cluster into each loop. You can then address each loop from anywhere in the application.
Of course, if at some point you were to remove 4, or perhaps you had a 4-lite, then it might make sense to keep it in your control loop so it makes more sense where to change/add the additional enqueue.
Design patterns are just that - patterns - sometimes you'll need to add to them/modify them to suit your application. When glancing at the code, it should be obvious what architecture you're using (e.g. QMH).
11-04-2015 10:20 AM
I disagree with Sam. In my discussions on the QMH I refer to loop 2 as the "marshalling" loop. Its primary job is to distribute messages to loops that need to hear them. Unless you are dealing with an extremely high throughput application where CPU cycles are critical, keeping all message marshalling centralized in one place really does improve the readability of your code, and helps prevent race conditions down the line, where there could be N different places that might be sending messages to a particular loop...things are a lot easier to understand and debug if there is one centralized location that distributes messages.
I discuss this topic in my 'Decisions Behind the Design of the Queued Message Handler' presentation, which you can view here.
11-04-2015 10:52 AM
I think Darren and myself have expressed the two opposite ends of the spectrum!
There are many situations where I have done as Darren describes (I have a medium application where I have a centralised 'message broker' which sends setpoint update messages to various different hardware modules) but in other situations I do as I first alluded to - cut out the middle-man and send the message directly.
I hope Darren at least agrees that neither answer is 'wrong' and there are pros/cons to each - the main thing is to document what you do so that it helps you to understand it later.
11-04-2015 10:56 AM
@Sam_Sharp wrote:
I hope Darren at least agrees that neither answer is 'wrong' ...
Hey, there are plenty of people who thing global variables are 'wrong', but I like them. 😉
So yes, abide by general rules when you can, but document your code when the exceptions come up. The general rules are there to keep you from shooting yourself in the foot. If you know what you're doing, sometimes the rules can be bent.
11-04-2015 02:35 PM
Combine 1, 2, and 4 into one loop and you'll be readable, resistant to race conditions, AND eliminate a lot of message passing.
11-04-2015 07:46 PM
I just use User Events instead of queues. Then each loop registers for the events they care about and everybody will get their own copy of the message.
11-04-2015 08:09 PM
@crossrulz wrote:
I just use User Events instead of queues. Then each loop registers for the events they care about and everybody will get their own copy of the message.
Is there a thread where you discuss this in more detail? I always wanted to learn how to do this...
Thanks!
11-04-2015 10:48 PM
@billko wrote:
@crossrulz wrote:
I just use User Events instead of queues. Then each loop registers for the events they care about and everybody will get their own copy of the message.
Is there a thread where you discuss this in more detail? I always wanted to learn how to do this...
The Delacor QMH implements inter-process communication with user events. It's a robust framework that builds upon the NI QMH, so it should feel pretty familiar to QMH users.
DQMH download (free on the LabVIEW Tools Network)
11-04-2015 11:30 PM
@Darren wrote:
@billko wrote:
@crossrulz wrote:
I just use User Events instead of queues. Then each loop registers for the events they care about and everybody will get their own copy of the message.
Is there a thread where you discuss this in more detail? I always wanted to learn how to do this...
The Delacor QMH implements inter-process communication with user events. It's a robust framework that builds upon the NI QMH, so it should feel pretty familiar to QMH users.
DQMH download (free on the LabVIEW Tools Network)
I am familiar with QMH. I can't wait to check out the vids and stuff. I think I have some idea of how it works. It will be very interesting to see how far off I am. 😉
Thanks! Kudo!