LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

producer consumer events with notifiers

Solved!
Go to solution

Dear LabView users,

 

I would like to ask your opinion about my project (see attached files). For beginning, I only made the "backbone" of my project, this is what you can see in my VI. My project will need to have the following functionalities:

 

-Start and possibly abort measurements (and also plot data to graph and record measurement data to file) --> there is a while loop to record data from DAQmx (USB6009), and another while loop with different loop rate to ramp up voltage output to a magnet's amplifier.

 

-During measurement, or when the system is Idle, the user is able to read in measured data files, and evaluate measured data, etc...(so there will be more functionalities...)

 

I decided to use Producer consumer structure with events and notifiers, and I also use dynamic user event to be able to communicate from the consumer back to the producer (where I have my state machine also in a shift register).

 

So please comment on my VI, what do you think? Maybe I should use the state machine (the shift register with the state cluster) in the lower loop? I could also use queue instead of the notifier, but since I only send commands, and parameter values, (no high speed data streaming) I guess the notifier is just fine?

 

Thanks for advice!

Download All
0 Kudos
Message 1 of 11
(4,296 Views)

I just thought it over again, and I think I just unnecessarily overcomplicated the design: I try to use the top while loop with Events only for capturing user events, and the state machine and everything else will be in the bottom while loop. In this way I do not need Dynamic event either...  

 

EDIT: But, it is also not really good, if I have my state machine "on" the bottom while loop, since it should only execute when it gets a command from the top loop. Therefore I cannot iterate through the STATES of my state machine...maybe I stay with this original version so far.... still any comments are welcomed 🙂 thanks!

0 Kudos
Message 2 of 11
(4,286 Views)

please have a look on this VI. In my command cluster, I have commands what should be read by the measurement loop, or only by the "file read and data eval" loop. Therefore, I use in both places a "Default" case where I do nothing.

I think this structure will fulfill my needs....still any advice welcomed..

0 Kudos
Message 3 of 11
(4,271 Views)
Solution
Accepted by Blokk

The code you posted looks like a solid start.  The architecture is very similar to the Continuous Measurement Sample Project which shipped with LabVIEW 2012.

 

A few things I noticed:

 

  1. I would typically use queues instead of notifiers (unless you want to only handle the latest command and not all commands in the order they were recieved).
  2. You don't need the shift register in the top (event structure) loop.  You are inadvertently sending a measurement length parameter along with other commands since you only overwrite the command.  This likely won't cause any problems for now but could be an issue later.
  3. I think user events are a great way to handle shutdown cases where the consumer loop is able to signal to the producer loop that the application needs to exit (this is the way we do it in the sample project).
  4. Your "Init" case confuses me a little.  All it does is read the Measurement length control and send a User Event to the event structure which in turn immediately enqueues a Measurement command. Any time I see a control in a consumer loop like this I get a little uneasy. Why not have the "start_measurement value change event" read the Measurement length control and send it as part of it's message to the consumer loop. Then the consumer loop can Init and tell itself to begin the Measurement.
  5. You may need to revisit your error strategy in the Measurement case. Currently you don't stop either loop if an error occurs and you use shift registers to preserve error information between loop iterations.  Consequently if an error occurs in one of those loops you may never hear about it.
  6. In general, using the error status as the primary way of stopping a consumer loop is a bad practice. I'd rather see a "Shutdown" command that causes the consumer loop to stop. It's more scalable and less likely to be triggered by accident.

 

Good luck with the rest of your application.

 

~Simon

Message 4 of 11
(4,266 Views)

Thanks very much for the very useful comments!

 

  1. I would typically use queues instead of notifiers (unless you want to only handle the latest command and not all commands in the order they were recieved).

I am happy only with the latest command, and I also disable those buttons which I do not want the user to click on it (I like disable property node for buttons, it can save enormous amount of programming and logic)

 

  1. You don't need the shift register in the top (event structure) loop.  You are inadvertently sending a measurement length parameter along with other commands since you only overwrite the command.  This likely won't cause any problems for now but could be an issue later.

You mean I do not need the shift register for the notifier ref wire? Or also I do not need it for the cluster wire?

 

  1. I think user events are a great way to handle shutdown cases where the consumer loop is able to signal to the producer loop that the application needs to exit (this is the way we do it in the sample project).

I will do it as you say.

 

  1. Your "Init" case confuses me a little.  All it does is read the Measurement length control and send a User Event to the event structure which in turn immediately enqueues a Measurement command. Any time I see a control in a consumer loop like this I get a little uneasy. Why not have the "start_measurement value change event" read the Measurement length control and send it as part of it's message to the consumer loop. Then the consumer loop can Init and tell itself to begin the Measurement.

You are right, I can initialize my hardware just before the measurement, inside the start_measurement case. So, I do not need the init case at all...

 

  1. You may need to revisit your error strategy in the Measurement case. Currently you don't stop either loop if an error occurs and you use shift registers to preserve error information between loop iterations.  Consequently if an error occurs in one of those loops you may never hear about it.

I will program error handling, beside when I make the DAQmx codes for this part, you are right.

 

  1. In general, using the error status as the primary way of stopping a consumer loop is a bad practice. I'd rather see a "Shutdown" command that causes the consumer loop to stop. It's more scalable and less likely to be triggered by accident.

Well, this "dirty trick" comes from one official NI template. But you are right, I will do proper shutdown event.

 

 

 
0 Kudos
Message 5 of 11
(4,261 Views)

 

  1. In general, using the error status as the primary way of stopping a consumer loop is a bad practice. I'd rather see a "Shutdown" command that causes the consumer loop to stop. It's more scalable and less likely to be triggered by accident.

Well, this "dirty trick" comes from one official NI template. But you are right, I will do proper shutdown event.

 

I use this "trick" all the time.  I've not had any issues.

0 Kudos
Message 6 of 11
(4,225 Views)

@drjdpowell wrote:

 

  1. In general, using the error status as the primary way of stopping a consumer loop is a bad practice. I'd rather see a "Shutdown" command that causes the consumer loop to stop. It's more scalable and less likely to be triggered by accident.

Well, this "dirty trick" comes from one official NI template. But you are right, I will do proper shutdown event.

 

I use this "trick" all the time.  I've not had any issues.


Christian is correct. The proper way is to use an explicit shutdown message. Relying on the error status can cause problems. Just because it hasn't happened doesn't mean it can't.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
0 Kudos
Message 7 of 11
(4,217 Views)

@Mark_Yedinak wrote:

Christian is correct. The proper way is to use an explicit shutdown message. Relying on the error status can cause problems. Just because it hasn't happened doesn't mean it can't.


Can a communication reference throw an error and then go back to working properly?  I've never encountered it.  Your consumer is useless and needs to shut down anyway if the communication reference becomes invalid, so you are going to have to write shutdown-on-error code anyway.  Also, not every consumer loop naturally requires the extra overhead of a command-message system; kill-the-comm-to-kill-the-loop works on loops that don't use a command enum/string.  Finally, if the consumer is in a dynamically-launched VI separate from the producer, then shutdown of the producer for any reason (including aborting) will invalidate the comm reference and trigger automatic shutdown naturally.  Which, if nothing else, avoids the annoyance of having to close the project to kill off the orphaned daemons.

0 Kudos
Message 8 of 11
(4,191 Views)
Hm, this also makes sense 🙂
0 Kudos
Message 9 of 11
(4,180 Views)

@drjdpowell wrote:

@Mark_Yedinak wrote:

Christian is correct. The proper way is to use an explicit shutdown message. Relying on the error status can cause problems. Just because it hasn't happened doesn't mean it can't.


Can a communication reference throw an error and then go back to working properly?  I've never encountered it.  Your consumer is useless and needs to shut down anyway if the communication reference becomes invalid, so you are going to have to write shutdown-on-error code anyway.  Also, not every consumer loop naturally requires the extra overhead of a command-message system; kill-the-comm-to-kill-the-loop works on loops that don't use a command enum/string.  Finally, if the consumer is in a dynamically-launched VI separate from the producer, then shutdown of the producer for any reason (including aborting) will invalidate the comm reference and trigger automatic shutdown naturally.  Which, if nothing else, avoids the annoyance of having to close the project to kill off the orphaned daemons.


All valid points.

 

I advise against exclusively using the error to stop the loop whenever there is an aspect of state or session in the consumer loop.  For me, more often than not, there eventually is a difference between a normal intended stop and an unexpected system failure that needs to stop (i.e. you may wish to preserve the state, put hardware into a different mode, give something time to finish before closing etc.).  If the messaging infrastructure is there then I think you should use it. Both the error and the stop command may trigger a move into the same stop state before stopping the loop but it's normally worth the investment to provide both entry points.

 

It's also feasible that a consumer may need to attempt to regain communication rather than stop (more common in networked applications).

 

The NI supplied Sample Projects only use the error to stop a loop that has a notifier read and a graph update in it. Since there is no state, no logic, and no hardware or file resources being used we determined it was appropriate.  For every rule, an exception. The message loops all have an explicit Exit message.

 

Good discussion. As with many things in programming, well informed reasoning often trumps the "rules" but following the "rules" will generally prevent headaches down the road (which you may never run into).

 

~Simon

Message 10 of 11
(4,164 Views)