From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How can a DVR created in a functional global called by the main vi and a dynamic vi retain it's data?

Solved!
Go to solution
We are having problems with DVR's being garbage collected at surprising times resulting in bugs.  I am aware that if a dynamic vi goes idle then DVR's it created are garbage collected.  However, what is surprising is that vi's which are not exclusive to the dynamic vi's call chain which also produce DVR's (in our case a functional global which is called by all sorts of vi's in our program including the dynamic vi) get garbage collected when the dynamic vi is closed.  I'm wondering if there's a way to ensure that DVR's created in the functional global are persistent even if they were created when a dynamic vi happens to be the caller of the functional global?

For example consider this pseudocode:

GlobalDataStorageFunctionalGlobal.vi(input: read/write, [int array] X)
{
  if write
     Create a DVR and put data X inside of it
  if read

      return DVR

}

foo.vi    // called dynamically
{
   call GlobalDataStorageFunctionalGlobal(write, [1,2,3])
}
Main.vi
{
   dynamicRef = open vi ref to foo.vi
   run dynamicRef
   close dynamicRef
   theDvr  = GlobalDataStorageFuncionalGlobal(read)
   //  I would expect "theDvr" to contain [1,2,3] but it is now INVALID!!!
}
0 Kudos
Message 1 of 16
(4,765 Views)

I believe that your problem lies in the fact that LabVIEW automatically destroys a reference when the VI hierarchy it was created in goes Idle.  My best guess is that when you close the reference for foo.vi (the one that was opened asynchronously by Main.vi) that any references created within foo.vi while it was running are also destroyed.  I haven't tried to duplicate this with sandbox code yet but I think I will give it a go.  I am curious if this would work better:

 

GlobalDataStorageFunctionalGlobal.vi(input: read/write, [int array] X)
{
  if create
     create a DVR
  if write
     put data X inside of it
  if read

      return DVR

}

foo.vi    // called dynamically
{
   call GlobalDataStorageFunctionalGlobal(write, [1,2,3])
}
Main.vi
{
   GlobalDataStorageFunctionalGlobal(create)
   dynamicRef = open vi ref to foo.vi
   run dynamicRef
   close dynamicRef
   theDvr  = GlobalDataStorageFuncionalGlobal(read)
}
Message 2 of 16
(4,742 Views)

Found a similar post here with a similar answer.

 

"All LabVIEW refnums are garbage collected as soon as the tope level VI in whose hierarchy the refnum was created goes idle. So if you have an initialize VI that is started as top level VI and which creates your DVR and semaphore and that initialize VI is started dynamically (which actors are as far as I know) and then it ends its merry task and goes idle, the refnum is destroyed and your other actors won't see a valid refnum object anymore.

 

So it is important to create those refnums inside the hierarchy that is going to use them or alternatively have a top level VI that stays active for the duration of the entire program executation and delegate the creation of those refnums to that VI or some subVI which runs in that hierarchy.  - Rolf Kalbermatter"  

 

 

Message 3 of 16
(4,738 Views)

Man, I apologize for the spam here, I blame it on multitasking.

 

If you take a look at this tutorial on closing refs in LabVIEW, there is a section called reference leaks where it states:

 

"If a Start Asynchronous Call function makes a call-and-forget VI call, that VI is a separate top-level VI."

 

So if you a are using the Start Asynch Call function  with call-and-forget to spin up foo.vi then LabVIEW is treating it as its own hierarchy, which would explain why closing foo.vi closes all refs created while foo.vi was running.

0 Kudos
Message 4 of 16
(4,726 Views)

Jon, I also found that forum post and the suggestion by "rolfk".  But isn't that what we're doing?  I assume rolfk meant "DVR" when they wrote "refnum" in this sentance:  "have a top level VI that stays active for the duration of the entire program executation and delegate the creation of those refnums to that VI or some subVI which runs in that hierarchy."  Isn't that what our functional global is?  If rolfk meant vi references should be handled by some top level entity then it's a different conversation and a discussion of how to avoid memory leaks comes into play.

 

I recognize that we're creating a new top level vi, so, the question is whether it's possible for that top level async vi to call another vi in such a way that that vi opperates according to the scope it would normally have if not being called by the async top level vi?  

0 Kudos
Message 5 of 16
(4,710 Views)

Hey Thomas,

 

I think that the distinction is that when a top level VI goes idle any refnums created within its hierarchy are closed, even if the VI that created the refnum is a functional global variable running in multiple hierarchies.  I put together an example using the Actor Framework, its attached and its in LV2015.  The example has two Actors, Actor A and Actor B.  Each Actor has one method, and all the method does is call the write action of a functional global variable.  Actor A calls FGV A, and FGV A has a write action that creates a DVR and writes an array of doubles to it, and it has a read action that reads the array of doubles out.  Actor B calls FGV B, and FGV B has a create action that creates the DVR, a write action that writes an array of doubles to the DVR, and a read action that reads the array of doubles out.

 

I set it up so that after Actor A is launched we send it a message to Write data to the FGV A, we then send Actor A the stop message, and finally we call the read action on FGV A.  This generates error 1556 (LabVIEW:  The reference is invalid. This error might occur because the reference has been deleted.) like you are seeing.

 

I also set it up so that the create action is called on FGV B, after which Actor B is launched, then we send Actor B a message asking it to Write data to FGV B, then we send Actor B the stop message, and finally we call the read action of FGV B.  This time, data is returned as expected and no error is generated.

 

DVR in FGV.jpg

 

This lines up with what you are seeing, and can be explained by the fact that what matters is within which VI Hierarchy the DVR refnum gets created, not the fact that FGV exists in both VI Hierarchies.

 

Does that help?

 

-Jon

Message 6 of 16
(4,688 Views)

So technically, yes, that solves the problem I posted in pseudocode.  By pre-allocating a DVR in the main application instance it isn't garbage collected.  Unfortunately we are actually building a queue of DVR's to data.  So pre-allocation is a bit impracticle in our case.   Thankfully I was talking with someone on another medium and they suggested what I believe will work for us which is to keep our call chain the same but rather than creating DVR's when we need them instead have an entity (Actor?) running in the main applications call chain whos sole purpose is to receive requests for persistant DVR's and return them.  So the Functional Global will request a DVR from this entity via messages and receive the DVR via messages in place of where it normally creates them.

 

Does that seem like it will work?

0 Kudos
Message 7 of 16
(4,675 Views)

@Thomas_robertson wrote:

I assume rolfk meant "DVR" when they wrote "refnum" in this sentance:  "have a top level VI that stays active for the duration of the entire program executation and delegate the creation of those refnums to that VI or some subVI which runs in that hierarchy."  Isn't that what our functional global is?


No, that's not what your functional global is, because your functional global doesn't run continuously. Active means the VI is actually running.
 

Refnum is slightly more accurate than DVR since this applies to a number of resources (such as queues and notifiers), not just DVRs.

0 Kudos
Message 8 of 16
(4,673 Views)

Ah... Ok, in that case the post I made just before yours about an entity that gets DVR creation requests and responds with them through messages is an implementation of what the author was suggesting, correct?

0 Kudos
Message 9 of 16
(4,669 Views)
Solution
Accepted by topic author Thomas_robertson

@Thomas_robertson wrote:

Ah... Ok, in that case the post I made just before yours about an entity that gets DVR creation requests and responds with them through messages is an implementation of what the author was suggesting, correct?


Yes, that would work. Although at that point it might be just as easy to create the DVRs in the actor but store them in the FGV, to minimize how much you need to rearchitect. Then you don't need to send a message to retrieve them, just to create them. Since the actor owns the lifetime and runs continuously (even though it's sleeping most of the time so not consuming any processing time), the references will continue to be valid.

0 Kudos
Message 10 of 16
(4,661 Views)