Jump to content

Proper style for passing session refnums and other similar data types in loops


Recommended Posts

I'm aware of this thread on passing errors around loops. https://forums.ni.com/t5/LabVIEW/Error-in-out-in-shift-register-yes-or-no/td-p/1077703

On a similar note, what is deemed the best way to handle wires containing references to devices or sessions in a loop? What are the pros and cons to consider?

I've made a few examples using the Vision AVI2 library, but the same thing could apply to an IMAQ camera session, or indeed a TCP/IP or serial communication session, where you need to initialize a session, do your core logic (the loop) and then shut it all down at the end.

In my case I already have the error cluster managing the function order execution. With that in mind, what's the best way to set up my wiring?

 

Using LabVIEW 2016, 64bit.

refnum_wiring_style.png

refnum_wiring_style.vi

Link to comment

(probably echoes what also said in the other thread): If the reference can become invalid in the course of the iterations, and I want to check it specifically at each iteration, I'd put a shift register; if it is sufficient to know what was the initial ref, I'll go for 1. or 3. If reference going invalid in the course of the execution of the inner VI implies an error at output, I'd put a shift register on the error wire.

But most importantly: if there is any chance that the loop executes 0 times, use 2., not 1.

Link to comment

Never do #1. Not because in this specific case its not fine (although its not) but simply because its a bad habit.

Its an incorrect form because if an error occurs on the AVI open (or on error in, or if the avi is empty) then N becomes 0. If N is 0, the for loop doesn't run. If the for loop doesn't run, the output avi refnum and output image refnum are both invalid, and thus you have a memory leak (unless this behavior has changed in the last few years). 

To summarize:
Error in->N=0 but no refnums are created->OK
Error on open ->Same->OK
Empty avi file->N=0 but both refnums created->Memory leak.

...which is why I say its awful hard to think about this every time so I just don't ever follow that pattern.

 

I personally usually go for 3 unless I'm doing something dynamic (VI server call, dynamic dispatch) where it isn't clear what could happen inside the loop. In this case the safer bet is a shift register. Always using a shift register also eliminates the risk involved in the for loop not running, but introduces the risk that you could accidentally invalidate the refnum yourself at some point (case structure, default value if unwired for example).

 

The error on the shift register depends specifically on what I'm doing. Like one commenter in the other thread mentioned I like to put a case structure in and never run the for loop if an error is coming in. I then like to either (a) immediately stop on any error, as you might do if you are processing frames in a video or (b) create an output array of all the errors which occurred, which you might do if you were batching some set of actions. I don't believe there is ever a good 'pattern' to follow for error handling because it always requires some level of thought.

 

Fun fact: did you know that imaq dispose image doesn't run if an error occurs upstream (at least according to the help)? And when I say fun, I mean I hate imaq so so much :( .

Edited by smithd
  • Like 1
Link to comment
  • 1 month later...

1) is bad form. It will cause an invalid refnum (and empty arrays and strings and 0 integer and floats) after the loop if the loop iterates 0 times. And yes, even if you think it will never be possible to execute 0 times, you always get surprised when the code is running somewhere on the other side of the globe and you only have a very slow remote connection that makes life debugging impossible.

2) is the prefered way for me for any refnum and most other data. Anecdotely LabVIEW had some pretty smart optimization algorithmes in its compiler that were specifically targetting shift registers, so for large data like arrays and long strings it could make a tremendous difference if you put this data into a shift register instead of just wiring it through. he latest versions of LabVIEW do have much more optimization strategies so that the shift register is not strictly necessary for LabVIEW to optimize many more things than before. However the shift register won't harm the performance either and is still a good hint to LabVIEW that this data can be in fact treated inplace.

3) is simply ugly although it doesn't bear the problem of invalid data after a 0 iteration loop (but can potentially prevent LabVIEW to do deeper optimization which for large data can make a real difference).

 

For error clusters 1) can be a possible approach although you still have the potential to loose error propagation on 0 iteration loops that way. You do need to watch out for additional possible problems when an error occures. One possibility is to simply abort the loop immediately which the abort terminal for for loops is very handy for, or to handle the error and clear it so the next iterations still do something. The least preferable solution is to just keep looping anyhow and do nothing in the subsequent iterations (through the internal error handling in the VIs that you call) BUT ONLY for For Loops!! Never ever use this approach in While Loops without making 200% sure that the loop will abort on some criteria anyhow! I've debugged way to many LabVIEW software where an error in a while loop simply made the loop spin forever doing nothing.

Edited by rolfk
Link to comment

I know the question is about references, but all of the shown examples is less than ideal for errors unless it is intentional to only look at the last iterations error, and to clear the error if the loop runs 0 times.  In cases like this I will either turn the error wire into a shift register (this will cause an error in iteration 0 to not allow iteration 1 to run, sometimes this is desired sometimes it is not) Or I will enable indexing on the error of the for loop, and use a merge error to turn it back into a scalar.  This way each iteration will still run without error, but my output will indicate if an error occurred on any iteration.

As for references, if the for loop runs 0 times the reference will be invalid if no shift registers are used.  In this case it isn't all that bad because to cause the for loop to run 0 times the second subVI needs to return a 0 which will most often happen if an error was pass into that subVI, in which case the reference won't be made, and won't be used anyway.  But in many other cases the number of iterations is defined by an indexing array, and if the array size is 0 you have the same issue of turning references invalid, and not being able to use or close them later.  Many developers don't think about the ways that the array could be of size 0 and assume that will never happen but it does.  Remember that if two arrays are being indexed, it is the minimum size between the two that defines how many times the for loop will run.  So if one is empty and one has 10 elements, the for loop runs 0 times, and references are lost again.  

This 0 running for loop can clear errors in some cases too.  In your #3 if the Error In is true, then the for loop will run 0 times, but the error also will be cleared which is also likely undesired.  Basically #2 or #3 are fine for references, but have slightly different behavior, which probably won't matter.

refnum_wiring_style_BD.png

Link to comment

A little off topic, but a few posts here describe loops behaving differently if an error is passed in by a shift register.

Some quick tests with both for and while loops showed no change for me. Is this just a reflection of the fact that most things inside a loop will check for an error and behave differently (often becoming no-op/passthrough)?

Link to comment
5 hours ago, Christian Butcher said:

A little off topic, but a few posts here describe loops behaving differently if an error is passed in by a shift register.

Some quick tests with both for and while loops showed no change for me. Is this just a reflection of the fact that most things inside a loop will check for an error and behave differently (often becoming no-op/passthrough)?

There is definitely a change depending if you use a shift register or not for the error cluster

                                                       with shift register                               without

error before loop (n >= 1)               n times do nothing                           n times do nothing

error before loop (n = 0)                 error is visible after loop                  error has magically disappeared

error in loop execution x of n          0 .. x -1 executes                             0 .. n executes

                                                        first error in loop is passed out        unless you create an autoindexing error array, only the last error of the loop execution is passed out

Generally only the purple situation in the loop without shift register for the error cluster is sometimes preferable above what the shift register would cause. The red ones are definitely not desirable in any code that you do not intend to throw away immediately.

Link to comment

Ah, thanks. The table clears this up a lot for me. I tried testing what you labelled as 'error before loop' with a stop control for a While loop or a constant wired to a For loop, and so (unwisely) never saw any difference. 

On the other hand, I did know that a For loop with 0 iterations will provide default outputs, so should have understood the problem with that row.

I'm now only confused by your 'error in loop execution x of n', 'with shift register' cell. Why would the loop stop executing in subsequent iterations? Is this different behaviour to passing an error into a shift register (from outside the loop, i.e. the (1,1) cell? 

I tried running this VI, but the indicator showed '4' (seemingly unlike what the table describes) and the error was shown in the indicator (as expected, and listed by the table)

https://s10.postimg.org/ejdr13o2h/err_test.png

(I can't seem to add an image. Not sure why - maybe new user restriction?)

 

Link to comment

I think what rolfk is trying to say, is if you have an error when i=2, then that error will be passed back when iteration is equal to 3, and passing an error into 99% of the functions that use the error in, will not perform the operation.  So if you have an error when i=2, you will still go to i=3 and i=4, but that same error will be passed around each loop iteration, and those other runs of the loop will likely do nothing (or very little).  You can code around this with clearing or ignoring errors but if that is what you wanted to happen, then you probably wouldn't use a shift register to remember the previous error anyway.  

The other thing that can cause a loop to stop is the conditional terminal, and in some cases the developer will wire the error to the stop, which will stop running the loop if an error is seen.  So if an error occurred with i=2, then the loop will not execute i=3, doing effectively the same thing but better, since it will not run the other iterations at all.

EDIT: Oh and I don't know of any restriction on new user file uploading.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.