I have a top-level VI (GUI and program flow) which calls several VIs (instruments that have to be available the whole time, receiving commands from other VIs) asynchronously. When the top-level VI closes, it sends a command via queue to the called VIs which then also exit. Should I close the references to these VIs as well?
I'm not sure when their execution is finished - what happens if I try to close a reference to a still running VI? What would be the best way to handle this situation?
There will be no problems closing the refrence of the VI which is running asynchronously.
As long as your application requires the VI to run even after user interface is closed there should be no problems else you can just terminate the VI execution also when the user quits UI.
I guess you are running the VIs with the "Start Asynchronous Call.vi". In this case you must use the 0x80-Flag (Call and forget) on the Open VI Reference Function. This Flag still doesnt force the client vi to dispose its reference, so:
Yes, you must close the reference manually.
But you should know, that you can close the Reference even before the client vi is finished running. With the 0x80-Flag, the VI will dispose its reference after finishing execution, but only if you closed its reference in the main vi before.
If you are not using the Start Asynchronous Call.vi, but using the "Run VI" Invoke Node on the VI-Reference, you can also start the VI asynchronously and set the "Autodispose Reference"-Parameter to true. In this case you must not close the reference manually. The VI will automatically close it after its execution.
You should have a look at the "Asynchronous Call and Forget.vi"-Example in the examplefinder. This shows the default usage of the Start Asynchronous Call.vi.
I hope this answers your question, if you have anything else that is unclear, just answer me!
Staff Applications Engineer
Hi, thanks for your replies!
I'm still a bit confused:
You mention that I should close the reference in the calling VI, but the target VI disposes of its reference after execution?
What is the difference between closing and disposing?
closing and disposing means basically the same thing. Let me explain again:
All assumed you use the Start Asynchronous Call.vi and the 0x80-Flag enabled.
You open the reference and run the VI. After that you have to close the Reference for sure. But it doesnt matter when you close it. You can either wait for the VI to finish, and close it afterwards. But (and this is not normal) you can also close the reference right after you run the VI. Normally closing the Reference to a VI aborts its execution. In this case not. If you close the Reference before the client VI has stopped, it will keep running, and then unload itself (thats what I ment with "dispose reference") after it finished.
This means, that you can't communicate with the VI anymore, since its reference in the main-vi is not valid anymore after closing. But it will be still running until its stopped. You need a good error/stop-handling in this case, and have to make sure, that the client VI will stop when you're finished.
Compared to that it would be easier with just dynamically loading the VI (without 0x80=Call and forget). In this case you can just close all references in the end and by that make sure, that all dynamic VIs are stopped.
In your case you have to take care of that yourself.
Yes, you need to close the reference to prevent memory leaks!
I hope that was detailled enough, if you have further questions, just let me know!
Staff Applications Engineer
I understood the principle now, but I still have trouble integrating that understanding into my software.
Let me explain what my program does and where the problem occurs:
I have 3 hierarchy levels:
1. Main VI with the GUI. Runs all the time. It calls other VIs asynchronously with the 0x80-Flag
2. Process VIs. I have different processes that I want to run asynchronously, but only when they are needed. Only one process at a time. Between execution of different processes, there can be idle time (waiting for user input for starting another process).
3. Instrument VIs. They also run all the time, generating readings.
Main VI : --------------------------------------------- Exit (--- indicates that the VI is running)
Process 1: ----- Exit
Process 2: ------ Exit
Instruments: ------------------------------------------ Exit
I use the continuous measurement and logging architecture. The instruments consist of a message handling loop each. The processes also, but they in turn control the instruments via their queues.
My problem is, that when the main VI is exited (just running the VI and then after initialization is finished immediately exiting without running any of the selectable processes), the instrument VIs don't stop running. Sometimes one of them stops, sometimes it doesn't. I get an "error 1", indicating an invalid queue reference. But the queue reference is released in the instrument VIs themselves, so I don't understand how it can be invalid. Basically the instrument VIs are told to stop, then they shut down all motors, finish their loops and release their queues...or try to.
It is difficult to show this all in screenshots, so I uploaded my VIs:
1. main_gui_v7... -> this is my main VI
2. IAI_message handling loop_v4 -> this is instrument VI #1
3. PI_message handling loop -> this is instrument VI #2
4. Call VI asynchronously -> this is my FGV to call different VIs
There will be many missing items, but it should suffice for an overview. If something is needed, just tell me so and I'll upload that as well.
The queue references are still valid when I set break points right after the press of the exit button and manually forward the execution until all VIs are done. Then it works, but not when it runs automatically. Does that indicate a timing problem?
I'm afraid, debugging a whole queued message handler is not really applicable for me. Its just too much effort reading into the whole code. But what you are seeing seems like a "normal" Queued Message Handler Problem.
But I can give you some tips on how to get closer, or what might causing this, while just looking at your main-vi.
-I can't find the Instrument-Process. Is it also an asynchronously started VI? You should consider just placing the subVI in the MainVI, since its supposed to run all the time anyway.
-You should find out what exact point in the code throws the error (Probes!)
-You are destroying the UI-Queue right after the UI Message Loop. Concider placing it in the end of your error line (next to the User Event Stop on the right). Maybe your UI loop runs once more and throws the error when not finding the UI Queue.
Please try some of these, I'm sorry I can't take care of debugging this, but it shouldn't have anything to do with dynamically loading VIs. If you Initialize a Queue in the Main VI the Reference will remain open until you close the Main VI or destroy the queue.
Please invest a little time in debugging with probes, and give me a short reply, if you get stuck again.
Staff Applications Engineer
If you Initialize a Queue in the Main VI the Reference will remain open until you close the Main VI or destroy the queue.
Thanks for that hint, I think that's it. I thought the queue reference would stay open even if the VI that created the queue is closed. When I delay the last loop of the main VI so that the instrument VIs have enough time to finish, the error is gone.
Thanks, I never would have arrived at that solution alone 🙂
Perfect, but delay sounds much like a workaround to me. Consider using a loop, thats currently reading the status of the queue, and continue only when the queue is destroyed properly. But if the delay works for you you can keep using it, just be aware, that timings might change in an executable, or on different PCs (or even with different Programs opened parallel to LabVIEW), so your static delay might get too short in the future.
I'm glad everything works, wish you the best for your Project!!
Staff Applications Engineer
We've been using a modestly-tweaked version of NI's QMH project template and have had great success avoiding the problem you're seeing. It comes about through a fairly simple convention we follow.
The main vi is responsible for calling Obtain Queue and getting live queue refs for all the auxillary message handling loops it launches. Each of these parallel processes is passed the ref to their own personal message queue. But each of those parallel processes becomes responsible for releasing its own message queue after its loop terminates and execution is about to stop. Each parallel process also accepts an "Exit" message that must cause it to terminate (not necessarily instantly though).
This has worked out quite cleanly. We haven't had problems needing to do waits or gotten stuck with hanging processes. The convention also extended nicely into a 3-level hierarchy where the 2nd-level process obtained a ref for its own private 3rd-level sub-process.
There are other approaches that could work, but now that we've settled on one that *does* work, we can just keep following the convention and not have to spend time thinking about it with every new project.