Jump to content
Aristos Queue

"Closing References in LabVIEW": New documentation published

Recommended Posts

National Instruments has published the canonical document on closing references in LabVIEW. This document codifies everything known about closing reference data types in one place and should be considered the definitive documentation for all questions thereto going forward. This supersedes any other documentation we may have published on the topic. If you find other documents that contradict this document, please CAR them or, if it is something like a forum post, refer them to this document.

 

Closing References in LabVIEW

http://www.ni.com/white-paper/14393/en

 

Share this post


Link to post
Share on other sites

In the previous example, closing the VI reference immediately before or in parallel to the second Open VI Reference function creates a race condition

 

Surely this is a "bug" that violates dataflow.

Share this post


Link to post
Share on other sites

"You can close child object references when you no longer need them, but closing the parent VI reference automatically closes child object references of that VI. However, if you close the parent VI reference before LabVIEW calls a child object reference, the child object reference may become invalid. Make sure to wire block diagram objects so each function executes in the order you want."

 

It wasn't immediately obvious to me that this applies to all parent references, not just to the (fairly obvious) case that the parent is a VI. To extend the example given, if you open a vi reference, get a reference to the panel, get a reference to the controls, close the panel reference, but leave the vi reference open, then the control references are invalidated. Now I'm wondering why I haven't fallen into that before.... :)

Share this post


Link to post
Share on other sites
because refs to actual controls can never actually be closed?

Um, well the refs in the Controls[] property of a panel reference presumably can and should be closed. The refs obtained via control reference nodes obviously not.

Share this post


Link to post
Share on other sites

Um, well the refs in the Controls[] property of a panel reference presumably can and should be closed. The refs obtained via control reference nodes obviously not.

There's nothing special about the refs obtained from the Controls[] property that makes them different than a regular control reference.  Each control has a unique refnum which will be returned whenever that control is referenced, regardless of how that refnum is obtained (direct reference, controls[] property, etc).  As a result, no need to close those references.  As an example, see the code below (note that you can create a direct reference to a control within a cluster).

post-3989-0-28858300-1357457306.png

Share this post


Link to post
Share on other sites
There's nothing special about the refs obtained from the Controls[] property that makes them different than a regular control reference.  Each control has a unique refnum which will be returned whenever that control is referenced, regardless of how that refnum is obtained (direct reference, controls[] property, etc).  As a result, no need to close those references. 
The implication is though that LabVIEW manages the implicit references but you manage the Controls[] references (by closing them or a parent)

Share this post


Link to post
Share on other sites
It wasn't immediately obvious to me that this applies to all parent references, not just to the (fairly obvious) case that the parent is a VI. To extend the example given, if you open a vi reference, get a reference to the panel, get a reference to the controls, close the panel reference, but leave the vi reference open, then the control references are invalidated.

 

This does not extend to all reference types. It only applies to the parent reference being a VI. In your example, closing a panel reference will not invalidate references obtained from the panel reference.

In the previous example, closing the VI reference immediately before or in parallel to the second Open VI Reference function creates a race condition

 

Surely this is a "bug" that violates dataflow.

 

The image with two Open VI Ref calls does not violate dateflow. Unless I am missing something, the diagram is syntactically valid. If you believe there is a bug, will you elaborate?

ned said:

There's nothing special about the refs obtained from the Controls[] property that makes them different than a regular control reference.  Each control has a unique refnum which will be returned whenever that control is referenced, regardless of how that refnum is obtained (direct reference, controls[] property, etc).  As a result, no need to close those references. 

 

This is not true. There are plenty of times you should close control references. That is one of the points of this document.

 

It is true that each control has a unique refnum. (At NI, we call it the "this" reference.) And it is true that that refnum is often returned by implicit references, properties, etc. Closing the "this" reference is a no-op so you can technically get a way without closing it.

 

However, there are numerous ways to obtain control references and not all of them return the "this" reference. There is not a good way to know if the reference you obtained is a "this" refernece (other than the few cases stated in the document) so it is best to just go ahead and close the reference.

Share this post


Link to post
Share on other sites
The image with two Open VI Ref calls does not violate dateflow. Unless I am missing something, the diagram is syntactically valid. If you believe there is a bug, will you elaborate?
 
It seems to say that opening a VI ref then closing it immediately before attempting to re-open by name (whilst linked via the error cluster) will cause a race condition. This should not be the case. The second call (by name) should always return an error in this example. If it doesn't, then it is violating dataflow since the ref should be at least marked as invalid if not completely removed from memory and, as there are no other open references, the second call should fail.

Share this post


Link to post
Share on other sites
However, there are numerous ways to obtain control references and not all of them return the "this" reference. There is not a good way to know if the reference you obtained is a "this" refernece (other than the few cases stated in the document) so it is best to just go ahead and close the reference.

To improve my own understanding, what is one way to obtain a reference to a control in a local VI (not accessed remotely through VI server) that returns a valid value other than the "this" reference?

Share this post


Link to post
Share on other sites
It seems to say that opening a VI ref then closing it immediately before attempting to re-open by name (whilst linked via the error cluster) will cause a race condition. This should not be the case. The second call (by name) should always return an error in this example. If it doesn't, then it is violating dataflow since the ref should be at least marked as invalid if not completely removed from memory and, as there are no other open references, the second call should fail.

 

ShaunR, I'm slightly confused by your most recent post. I'm assuming the third quote attributed to me was actually your comment. I'm responding to that.

 

It may surpise you, but yes, there is a potential race condition there. Assuming the reference is the only thing holding the target VI in memory, the second call (by name) might return an error but it also might succeed.

 

Several LV releases ago, the Close Reference function was always asynchronous making it very common for the target VI to briefly remain in memory after the close. Somewhere around LV 8.2, I made a change that made the Close Reference synchronous much of the time. The keyword here is much. There are a variety of things that can determine whether or not the Close Reference will immediately.

 

So, if the Close Reference determines it cannot immediately dispose of the target VI, the referenced code is a race condition.

To improve my own understanding, what is one way to obtain a reference to a control in a local VI (not accessed remotely through VI server) that returns a valid value other than the "this" reference?

 

The most obvious way is via the Open VI Object Reference node. If you call this several times targeting the same object, you will get a different reference each time.

 

There is not a great way to know you are getting a new reference each time because the comparison primitives compare the target, the reference. If you really want to verify you are getting different references, typecast each reference to an int32. Viewing it has hex makes it a little more human readable.

 

Most property/invoke nodes that return object references return the "this" reference. However, not all of them do. It is safest to go ahead and close the refs.

Share this post


Link to post
Share on other sites
This does not extend to all reference types. It only applies to the parent reference being a VI. In your example, closing a panel reference will not invalidate references obtained from the panel reference.

Yeah, I realized after the event that I'd messed up my quick test code and was being misled as to why my references were invalidated.

Share this post


Link to post
Share on other sites

I have a quick and probably very dirty test that I use (I really hate seeing code with a bazillion close references on there).  I will Type Cast the reference to an unisigned integer.  VIs, Projects and the like give you a different value each time you run, those references I close.  Others, such as controls and panels give the same value each time, those I do not close.  Works for me so far.

 

Also, it is shown in a picture, but it should be spelled out more explicitly that Close Reference does in fact accept arrays (why not clusters?) which can clean up a lot of code.

 

Probably worth mentioning one other rule I try to follow at all times in subVIs:  If you didn't open it, don't close it.

Share this post


Link to post
Share on other sites
National Instruments has published the canonical document on closing references in LabVIEW. 

 

And here's the guerrilla guide:

  1. Take a good stab like a jolly good sport at closing all your references
  2. Every blue moon when you run into a bug caused by improperly closed references, run Desktop Execution Trace Toolkit and take 5minutes to fix the yellow rows. Prosper.

:yes:

 

Now the *tricky* part comes with, not closing your references -- but keeping references open -- by understanding lifetime w.r.t. dynamic processes. I'm still refining my understanding and best practices to deal with this limitation.

  • Like 1

Share this post


Link to post
Share on other sites
Probably worth mentioning one other rule I try to follow at all times in subVIs: If you didn't open it, don't close it.
This is my general rule too, though there are exceptions where documentation clearly states references returned must be closed.

There are also less clear cases-- the XML library is particularly finicky/inconsistent in my opinion, but this is likely due to the underlying third party binaries rather than LabVIEW.

Jack's point is very good. The desktop execution trace toolkit is very valuable for tracking reference leaks.

  • Like 1

Share this post


Link to post
Share on other sites
ShaunR, I'm slightly confused by your most recent post. I'm assuming the third quote attributed to me was actually your comment. I'm responding to that.

Indeed. Ever since lavag.org went off and came back again. The reply editor has been kind of screwed in Firefox (well Waterfox actually) for quoting (using Chrome now ;) )

 

 

It may surpise you, but yes, there is a potential race condition there. Assuming the reference is the only thing holding the target VI in memory, the second call (by name) might return an error but it also might succeed.

Several LV releases ago, the Close Reference function was always asynchronous making it very common for the target VI to briefly remain in memory after the close. Somewhere around LV 8.2, I made a change that made the Close Reference synchronous much of the time. The keyword here is much. There are a variety of things that can determine whether or not the Close Reference will immediately.

 

So, if the Close Reference determines it cannot immediately dispose of the target VI, the referenced code is a race condition.

Then my statement stands. It is in violation of dataflow.

Share this post


Link to post
Share on other sites

Good to know! Made immediate use of that. Thanks.

 

Our test lab here mostly uses a generic, all-purpose LabVIEW program which I've been adding to and modifying the past three years. There are umpteen channels of each kind of cDAQ module we have in house. All are addressed via reference. Over the years it had grown...and grown...and grown yet more into quite a LOT of references. So things were starting to bog down from the overhead to such a degree that some of our slower PCs didn't like to run it at all  (still a few Dell GX620's in service).

 

So I was just recently getting around to writing a VI for to strip away, on the fly, unused channels from the arrays-of-clusters-of-references just before those outermost array's wires enter into the main execution loop.

 

Armed with the handy info posted here, it was easy enough to also close the references inside said strip-away loop. Very timely indeed. Thank's for posting it.

Share this post


Link to post
Share on other sites

Sorry for bringing this up again. My questions regarding closing references is towards references that are generated (opened) in the init state of an application and then transferred in to some kind of data type where they are being kept available to use at one's heart's desire. A regular use of this scheme is to get all FP element references of the UI at startup and passing them into a variant using its attributes. This way one can call on the attribute of that variant wherever wanted to retrieve the desired control reference. A function that does that can be seen here.

 

Question 1:

Within the functionlinke above, do I close the control references or will that make them invalid afterwards and therefore render the variant attributes useless? In other words - is the value on the wire of the reference a reference to THE actual control reference or is it THE reference itself?

 

Question 2:

According to the rule not to close any parent references before all actions on their child references are completed, the attached function should never leave me with usable control references. Yet it does. All the time. Without ever failing me. How come?

Share this post


Link to post
Share on other sites

So no one has ever told me this, but from what I've seen child references won't be closed using a close reference, if a parent is forcing them to stay open.  

 

Make a new VI, drop down a control of any kind.  Right click and create a static reference to that control.  Use the Close Reference on that reference, then use a property node to read the label text of the control, passing the error out of the Close Reference into the error in of the property node.  Now run the VI.  The label is still returned, and the reference is still valid even through you asked to close it.

 

This is because even though you asked to close the reference, it needed to be open because the VI that uses it is still in memory.  Reading the detailed help on the close reference function has more information on this.  This might also be compounded by the fact that I think this is an example of a "This" reference.

 

So closing the control reference in my mind does nothing, unless you explicitly opened the reference using the Open VI Object Reference.  So if you opened a reference to a VI, then used a property node to return the control references on the front panel.  Then it is my understanding that you don't need to close the control references, when you are done.  All you need to do is ensure the VI reference you opened gets closed.  As a fun test I'll usually write a simple VI that does my work and closes the things I think it needs to close, then use the Run Continuous button and look at the task manager and see if memory increases.  This is the only time I find myself using this button.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks Hooovahh and rolfk for your answers.

Summarized in terms of my questions:

 

Concerning Question 1: I don't need to close the references, but I may - closing static refnums is in fact a NoOp function

Concerning Question 2: It will always work, because the acquired refnums point to child elements of the FP and are therefore static refnums. See answer to Question 1.

 

Correct?

Share this post


Link to post
Share on other sites

Join the conversation

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

Guest
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.