12-21-2020 12:08 PM
The basic setup: I've got two VIs running in parallel. VI1 is the main VI, and VI2 is launched dynamically from VI1 (and is displayed in a subpanel). On close, VI1 waits for VI2 to complete before it stops. In order to share data between these VIs, I've been using a DVR. Since VI1 initializes the DVR, the DVR stays in memory throughout the lifecycle of VI1 and I'm able to read data back from it in VI1 before it closes.
Then I made things more complicated: I updated the data of the DVR to be an array of DVRs.
With this setup, VI2 is able to create new items and add them to my DVR of DVRs, and everything works great. That is, until it's time to close VI2. When this happens, the DVRs that were created by VI2 are no longer valid, and I'm unable to access the data in these from within VI1 (I get error 1556 when I try to access the data).
I've tried a few things (such as creating these new DVRs in a functional global), but without any success. Any suggestions? My guess is that garbage collection is cleaning up the DVRs from VI2 as soon as it leaves memory, but I'm at a loss for a good way to get around this issue.
Many thanks!
12-21-2020 02:36 PM
What you describe makes perfect sense.
You know that you need to keep VI1 open in order for DVR's made by VI1 remain in memory.
Why do you think VI2 would act any different with DVR's made by it?
If you have a VI that creates all DVR's, and keep it open, then you shouldn't have a problem. You say you did that with an FGV, but it didn't work. Why don't you attach the code that you say doesn't work so we can figure out why it didn't work? My guess is that you didn't program it the way you thought you did.
12-21-2020 05:31 PM
I think he understands the issue, he's just looking for a way around it.
Unfortunately I don't think there's a simple workaround here. See this thread for some previous discussion:
https://forums.ni.com/t5/LabVIEW/When-are-DVRs-automatically-deleted/td-p/3240205
Is the number of DVR's known in advance, or do the dynamically called children make an arbitrary number of them? If it's known ahead of time, just have the caller create the DVR(s) for the child when it gets launched. If it's not known ahead of time I don't think you can have your (dynamically launched) child spawn the DVR, and you'll need to implement some sort of messaging architecture to communicate between the processes. In general, having a messaging system between callers and dynamically launched children is a good architecture to use (see the Actor Framework or any of the QMH design patterns).
What kind of data are you communicating over these DVR's? Maybe there's a better way to do it that doesn't involve creating multiple DVR's at runtime.
12-21-2020 06:45 PM
You nailed it @BertMcMahan.
Due to the need to dynamically create an unknown number of new DVRs in VI2, I can't create them in advance. And due to the nature of what I'm doing (the 2 VI explanation was an over-simplification), I really do need the two levels of DVRs.
I'm in the process of re-architecting to message back to the main VI to have it create the DVRs on demand and pass them back, but was really hoping that I could avoid this otherwise unnecessary complexity...
12-22-2020 11:13 AM
Sounds like you could use a functional global...
I'd look for ways to completely refactor the DVRs (and functional globals) out. But that would require full understanding of the entire problem.
12-22-2020 11:30 AM
I would have expected a simple functional global to work as well, but it didn't -- it seemed like the life of the DVR was determined by the VI (or thread) calling the functional global. (The functional global did successfully create and store the DVR -- it was just that the reference would become invalid once I closed VI2 from the original description (even though both VI1 and VI2 used the functional global).
I ended up just spinning off a temporary parallel queue-based process that would do nothing other than create DVRs on request and keep them in memory until I was done with the DVRs. Unlike a functional global, this VI would remain running the entire time, which seemed to be key.
12-22-2020 11:39 AM
@_carl wrote:
I would have expected a simple functional global to work as well, but it didn't -- it seemed like the life of the DVR was determined by the VI (or thread) calling the functional global. (The functional global did successfully create and store the DVR -- it was just that the reference would become invalid once I closed VI2 from the original description (even though both VI1 and VI2 used the functional global).
A LabVIEW reference (almost any type) is closed once the top level data space of the creating VI stops.
This is well defined behavior.
@_carl wrote:I ended up just spinning off a temporary parallel queue-based process that would do nothing other than create DVRs on request and keep them in memory until I was done with the DVRs. Unlike a functional global, this VI would remain running the entire time, which seemed to be key.
Ah, the broker pattern.
That works, but the hard part is to make it stop when it's not needed anymore.
You can keep it running, but at some point you'll get an annoying popup that closing LabVIEW will close some running VIs.
02-16-2023 08:19 PM
Hi Wiebe@CARYA,
I just faced a similar issue, and something that helped me (other than reading your posts and your feature request, which I already kudoed) was before closing the process that created many of your DVRs, you would need to regenerate those DVRs from the process that will remain executing. This will act as passing the ownership over that data from one top VI to another. And it is an operation fairly simple, where you would need just to access its content, and then create a new DVR and replace it in your array of DVRs, all of this from the process that you are planning on kepping alive.
Let me know if this makes sense to you.
02-17-2023 03:18 AM
@Guillermo.O wrote:
Hi Wiebe@CARYA,
I just faced a similar issue, and something that helped me (other than reading your posts and your feature request, which I already kudoed) was before closing the process that created many of your DVRs, you would need to regenerate those DVRs from the process that will remain executing. This will act as passing the ownership over that data from one top VI to another. And it is an operation fairly simple, where you would need just to access its content, and then create a new DVR and replace it in your array of DVRs, all of this from the process that you are planning on kepping alive.
Let me know if this makes sense to you.
Yes, that's a way to deal with references. Creating them in something that keeps running is required. It's often trivial, but if it isn't it can be puzzling. You can make a broker for that (a dynamically running VI, that in turn does need to close at some point).
Beside the life time of references, by using anything by reference (incl. locals, (functional) globals, property\invoke nodes), you introduce a risk of race conditions.
Pure by wire programming cannot have race conditions. Of course you need some 'side effects' (done with terminals, locals, prop\invoke nodes, CFLN, etc.), but the fewer you need, the easier they can be managed (to avoid race conditions).
02-17-2023 09:31 AM
How about a single DVR to a map. Then access data by the key name of the map.