LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

queued msg handlers and ActionEngines

Hello, 

I am willing to learn good LV practices from the more experianced ones. Therefore I am asking about how you handle the following scenario. I often use a kind of queued msg design pattern with dynamic user events and queues to handle comm between loops. I do it similarly as for example in the "cont. logging and acquisition (daqmx)" design template. Last year i got the info from NI that they will create documentation in the close future, however as much as i know it is not done yet. I have a kind of feeling about that design it is somehow "patched", i do not find it elegant how the possible race conditions are eliminated in the msg handling loop (for example to avoid double hw init, etc.).

 

How do you solve these issues in your applications? For example nowadays i tend to use AEs which contains some state memory to avoid double init or close operations. Or it can also avoid the possible problem if there is still one more read HW state in the queue after closing reference (the AE ignores read request if the hw is already closed). Do you think it is a good practice to protect AEs in this internal way, instead of checking state status in the main vi? I find the above design template difficult to read with the nested enum checks in the gui msg handler loop. Are there better ways/ templates to use for such tasks?

Thanks for any idea and thoughts!

0 Kudos
Message 1 of 15
(2,952 Views)

I'm not finding that example. Can you either link it, or throw together a mockup vi showing what you mean?

 

Edit:  Scratch that. It is a project template, not an example. 

0 Kudos
Message 2 of 15
(2,939 Views)

Continuous Measurement and Logging (NI-DAQmx) Documentation.html

Yes, sorry this is a project not a template.

 

Main_BD.png

0 Kudos
Message 3 of 15
(2,926 Views)

Yea, sorry - I finally found it.  The version in 2014 looks a little bit different though. Perhaps NI finally updated it.

 

I'm going to preface this with:  I'm not exactly an expert. I have been working on learning design practices as well and this messague caught my attention.

 

OK, so looking at it, I'm not sure how you would run in to "race conditions".  The "UI Message Loop" and "Data Display Loop" are purely queue driven - which by definition can't have race conditions.

 

That having been said, I don't like this architecture for several reasons.

 

  • I find it bad practice to end loops with only error messages, because if you still have queued items they get lost when the queue is destroyed. In this case it is only data display, but if it was doing data logging or something...
  • It seems needlessly complex. A lot of the things they created a "message" for could easily be handled inside of the event structure. If you know your code is going to execute almost instantly, it makes no sense at all to send pointless extra messages for overhead. Especially if you already wrote a sub-vi to do this.
  • I prefer to use type defined enum constants for messages instead of text. The effect is the same, but it processes faster and you don't need to worry about typos.
  • I don't like the combination of the message handler and state machine. It again seems needlessly complex to me.
  • I don't like that one loop basically = the entire program. If something hangs or freezes or even slows down there (something that may be related to GUI control instead of acquisiton) you run the risk of buffer overflow happening and losing data. It just seems like a bad idea to me.

 

My method to do something very similar was as follows:

  • 3 loops - like they have.
    • "GUI" loop. This brought up all of my pop up windows, processed all of the GUI events, etc. It would send queued commands to the second loop to start / stop acquisition, setup hardware, etc.
    • Acquisition loop. This did all of my I/O, and PID. (program did acquisition and control).  This had (obviously) to be a tight loop for control and I didn't want it to ever have to worry about needless overhead anything.  Once data was acquired it would send a message down to loop 3.
    • Datalogging / Display loop.  This did all of the normal "overhead" for my program. Logged stuff to file, updated graphical display, etc.

 

Anyway, again: not an expert. Just my comments.

 

Edit: A word.

Message 4 of 15
(2,914 Views)

hm, tomorrow i will have a look on the LV2014 version too.

0 Kudos
Message 5 of 15
(2,908 Views)

@Blokk wrote:

hm, tomorrow i will have a look on the LV2014 version too.


Don't bother. I didn't have the "DaqMX" version open. The two are almost identical.

 

I also didnt look at the project close enough. They actually do acquisition and data logging in their own separate loops, so one of my comments is null. They also went out of their way to not stop those loops with just queue destroy, but instead put logic in to make sure all of the data was collected.

0 Kudos
Message 6 of 15
(2,894 Views)
I have found that trying to combine events with queues is (perhaps inherently) problematic. Remember that even though you often don't see them, there are event queues. Be careful about translating methodologies from languages. As I have written in the past, I believe that the only reason the producer consumer pattern that ships with LabVIEW uses queues is because it is traditional to build then that way in other languages. A possible alternative is that in the training classes NI wants to introduce the producer comsumer pattern very early, and before they have introduced events.

Mike...

Certified Professional Instructor
Certified LabVIEW Architect
LabVIEW Champion

"... after all, He's not a tame lion..."

For help with grief and grieving.
Message 7 of 15
(2,881 Views)

One of the reasons the standard QMH is the standard QMH is that it lets you talk to it from anywhere. If you take a a look at some of the RT sample projects you'll notice the same exact pattern over and over again because you can have your main loop sent messages from a UI thread, from the network, or from any random process running in your code. Thats the advantage. A good example of this would be the RT sample projects or this cRIO vibration logger (https://forums.ni.com/t5/Example-Code/Embedded-High-Speed-Data-Logger-Reference-Design/ta-p/3996474)... Also, in most applications I've worked on the QMH typically acts as the supervisor for the system but doesn't have a ton of the logic.

 

On the flip side there are many situations where you don't really need that flexibility, and its better to just use one event loop with some worker threads, or use user events to send type-safe data between processes.

 

You might also take a look at TLB prime which is a different kind of state machine template which distinguishes carefully between the state machine conceps and the QMH concept. I tend to think its overkill but then I primarily work on cRIO-type-applictions while the developer (Norm) tends to work on more complex front end applications. Worth a look, anyway.

 

 

 

 

Message 8 of 15
(2,846 Views)

"or use user events to send type-safe data between processes."

But for that, we need an Event structure in the separate process in order to receive Dynamic user events from the MAIN vi, yes?

 

thanks for all for the comments and ideas, I will also have a look on the LAVA template...

Best Regards,

0 Kudos
Message 9 of 15
(2,818 Views)

Personally I recommend the JK I "State Machine" as a great design of a queued event handler, adding User Events to carry messages.  I am not a fan of the NI sample project for multiple reasons.   In fact, I redid "Continuous Measurement and Logging" (2012 version) as an alternate sample project available after one installs my "Messenger Library" (it will be available as "Messenging: Continuous Measurement and Logging" if you install "Messenger Library").

Message 10 of 15
(2,802 Views)