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.



Link to post

(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 post

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 post
  • 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 post

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.


Link to post

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 post
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 post

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)


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


Link to post

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 post

Join the conversation

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

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.

  • Similar Content

    • By jhoehner
      Hello All,
      First time LAVA poster here with my first question. Why do some LabVIEW programmers insist on wiring the error cluster to the bottom of their VI as opposed to the sides as shown in most NI documentation. Is there any benefit to it? Is it 100% a preference thing? Is there a way to make LabVIEW connect error wires like this automatically?
      I've only seen it in advanced LabVIEW code from experienced programmers and some parts of the Actor Framework.
      Your insight and experience is appreciated! 

    • By the_mitten
      The introduction of parallel, read-only access for DVRs in LabVIEW 2017 adds a great deal of flexibility to using DVRs to monitor values in parallel executions of code. Fo\The downside of this, of course, is the necessity of using the In Place Element (IPE) throughout your code simply to read the value. Having IPEs throughout your code just to read a value both takes up block diagram real estate and also takes more clicks than desirable to insert.
      Similarly, though less frequently, there are times when you only need to update the value within a DVR without actually performing any logic inside of the IPE.  This situation is less frequent, at least for me, as I am usually using arrays or classes with DVRs such that I actually need to modify the existing data rather than simply replacing it.
      A more preferable solution to the above situations would be to have Read/Get and Write/Set VIs for the DVRs to simplify the process of working with them. This way, and IPE on the block diagram would only be needed when you were actually modifying the existing data within the DVR, rather than simply overwriting or returning the current value.
      Thanks to the power of malleable VIs and the type specialization structure that is now officially released in LabVIEW 2018, a better solution is now available. I’ve created two malleable VIs, Read  DVR Value (Parallel) and Write DVR Value that allow you to perform a write and a parallel read on any DVR data type.
       Now, you can use a single VI that you can insert via Quick Drop to read or to write DVR values.  
      Download the attached ZIP file to access the two malleable VIs and example code, and please let me know your thoughts in the comments!

      DVR Read and Write VIs 1.0.0.zip
    • By takanoha
      I have a simple program which has only 2 buttons for the user interface. When the user clicks OK I want the program to get into the event structure case called "OK Button". Once it is inside there is a loop which continuously waits for 1 second until "Stop Button" is called from the user. 
      But because once the user presses the "OK Button" the program gets into the event and therefore I can not call the "Stop Button". 
      Is there a way to call the "Stop Button" even if the program is inside the event ?

    • By Huqs
      Hello Labview Users, 
      I happen to have thousands of csv data file that I work with. The only way I recognize them is putting their characteristics in the file name. Which brings the problem of making the names too long and Microsoft doesn't like to accept long name. So I wanted to build a database for all my files. I am in the preliminary stage of building it ( I have attached the file and some of you may have seen it before). 
      What I want to do is, have all my files in the database with random names and list them based on their characteristics. I want to do that in my application in the place of 'file' box. So that I can click on the file and run it (double-click on the file in application to make them work in active file). based on the parameters listed on the database I want to filter them to find any specific file. How the interface of database should look like is shown blow (Image) . 
      It doesn't have to be a real database, just a directory application. I am trying to make it without the database toolkit.  If anyone can help me out and guide me out or guide me in the right direction then that would be great. Thanks. 

      Multicolumn list box v1.5.vi
    • By Zyl
      Hi everybody,
      I'm actually running on a problem with a  TCP connection between 2 cRIOS.
      One cRIO is a server which writes 76 bytes long messages every 10ms (today, but can be anything between 1ms and 1s) using STM Write VI (so at the end it pushes 82 bytes long message in the TCP write function). I want that message to be sent only if the client as time to read it, so I set the timeout to 0.
      The other cRIO is a the client with tries to read on the TCP link at a speed of 1000Hz (1ms, Wait next Multiple used to ensure that the loop is not running faster). I use the STM Read VI to get the data sent from the other cRIO. The read function has a timeout of 100ms.
      What I was expected is that the client loop would actually runs at 10ms rate (server writing rate) due to the 100ms timeout. And if the server writes faster, it would follow the server rate. If the server rate is greater that 100ms, error 56 would be fired, and I would handle it.
      What happens is that the server writes the 82 bytes every 10ms. But the client loop is always getting data and runs at 1ms ; which means that the timeout is not respected ! I disabled Nagel algorithm on the server side to be sure that the message is sent when requested, but it didn't help. The client acts like there is always data in the read buffer. Even if it can be right for the first iterations, I would expect that running at 1ms rate, the client would empty the buffer rapidly, but it seems that it never ends... Moreover, the longer the server writes, the longer it takes for the client to see empty buffer (timeout reached again and error 56) when the server is stopped (but connection not closed).
      Does somebody already ran into this issue ?
      Any idea on how I can solve this ?
      Server code is attached to the post. 2 TCP connections are established between the server and client (so same IP address, but different ports), but only one is used (upper loop). The other opens and close immediately because EnableStream boolean is always false.

  • Create New...

Important Information

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