Jump to content

Dynamic Calling


Recommended Posts

Top: Start Asynchronous Call - Loads a VI, starts running the VI, and then waits for it to complete.  The SAC returns as soon as the VI has started to run.  The Wait On Asynchronous Call is what waits for the VI to complete and return its outputs.

Middle: Call By Reference - Loads a VI and runs it.  The CBR will not return until the called VI is complete.

Bottom: Run VI Invoke Node - Loads a VI and runs it.  If you wire FALSE to the Wait Until Done input, the VI runs asynchronously.  If you wire a TRUE to the Wait Until Done input, the invoke node will not return until the VI is complete.  You do not have a direct way of getting the results once the VI is complete.

  • Like 1
Link to comment

There's also a little known feature in the top method where you can right click the Wait On Asynchronous Call and can set a timeout.  This will then wait some amount of time for the VI to finish and will generate an error if it isn't completed yet.  There are better ways to handle knowing when the VI is done, but it is good for a quick and dirty solution to wait a few ms for it to finish, and if it isn't done, go service something like the UI and come back again later.  I submitted that as an idea on the Idea Exchange, then AQ said why it was a bad idea.  Only for years later it to be implemented anyway.

  • Like 2
Link to comment

The top one, the SAC, will run even if the root loop is busy, AND allows you to set the inputs. This function was not available in LabVIEW until version 2011 or so. It is especially useful if you need your application to spawn VI clones to handle various events (TCP session handlers for example) regardless of what the user is doing in the GUI...

The two bottom ones will be blocked if the root loop is busy, e.g. if the user happens to be viewing the time picker of a time control it will halt until the user closes the time picker.

Before the SAC was introduced in LabVIEW you had to use the run method (bottom one) if you wanted to avoid having to wait for the dynamically launched VI to complete (it has the Wait until done input). The Call by reference node on the other hand had the advantage over the run method of offering control inputs to the call whereas the run method would require you to use set control invoke nodes for that. 

Here is a long thread about the root loop issue from before the SAC was introduced:

https://forums.ni.com/t5/LabVIEW-Idea-Exchange/Calendar-control-that-does-not-block-the-GUI/idi-p/1417794?search-action-id=359039184054&search-result-uid=1417794

 

Edited by Mads
  • Thanks 1
Link to comment
18 hours ago, Mads said:

The top one, the SAC, will run even if the root loop is busy, AND allows you to set the inputs. This function was not available in LabVIEW until version 2011 or so. It is especially useful if you need your application to spawn VI clones to handle various events (TCP session handlers for example) regardless of what the user is doing in the GUI...

The two bottom ones will be blocked if the root loop is busy, e.g. if the user happens to be viewing the time picker of a time control it will halt until the user closes the time picker.

Before the SAC was introduced in LabVIEW you had to use the run method (bottom one) if you wanted to avoid having to wait for the dynamically launched VI to complete (it has the Wait until done input). The Call by reference node on the other hand had the advantage over the run method of offering control inputs to the call whereas the run method would require you to use set control invoke nodes for that. 

Here is a long thread about the root loop issue from before the SAC was introduced:

https://forums.ni.com/t5/LabVIEW-Idea-Exchange/Calendar-control-that-does-not-block-the-GUI/idi-p/1417794?search-action-id=359039184054&search-result-uid=1417794

 

One small correction. The Open VI Reference will block on UI Rootloop even in the first (top) one. The Run Asynchronous method will however not incur a rootloop round trip.

  • Like 1
Link to comment

Thank you all for your answers

In the end, only the first one is useful. Is there a case where I might prefer the 2nd or 3rd solution over the first?

In fact, the 2nd solution will always be waiting for the end of execution, even if you set the option to call and forget

494167725_DynamiqueCalloptionx80.PNG.da66e8b28664f8fa41de9608227f9a83.PNG

 

Link to comment
2 hours ago, Rolf Kalbermatter said:

The Open VI Reference will block on UI Rootloop even in the first (top) one.

There's obscure "Run At Any Loop" option, being activated with this ini token:

showRunAtAnyLoopMenuItem=True

Firstly mentioned by @Sparkette in this thread:

I've just tested it with this quick-n-dirty sample, it works.

2024-03-05_16-04-47.jpg.df3ed79c29de67916906efa6d163076a.jpg

Also some (all?) property and invoke nodes receive "Run At Any Loop" option if RMB clicking on them. But from what I remember, not all of them really support bypassing the UI thread, so it needs to be tested by trial and error, before using somewhere.

Link to comment

I have another question about the attached image. 
I have a VI (I'll call it Test.vi) that dynamically calls an error monitoring VI. The function of this VI is to stop the calling VI in the event of an error. If there is no error, the calling VI closes the called VI using a boolean reference. 

In my main program, the "test.vi" VI was in a condition structure, and my code worked. I decided to call test.vi dynamically, and was surprised to find that my error VI never closed. The reason, I think, is that the reference is destroyed when the VI is no longer in memory, so I never see the true state of the Boolean. So I added an OR with not reference. And it works. 

I replaced the boolean reference with the reference of the calling VI, and looked at the Execution.State prorpiety node VI. Again, it worked. 

I tried to put my VI test.vi back into the main program without a dynamic call, and it no longer worked. The Execution.State always returns a running state, even when the VI is not executing. 

I have two questions:
- Why is the VI running when it's not executing? Even if I close the reference, it doesn't change anything.
- Is there a method or property node other than Execution.State that lets me know if the VI is actually running?

I don't know if I've made myself clear...

Reference in Dynamic Call.png

Link to comment
On 3/5/2024 at 7:32 AM, Francois Aujard said:

Thank you all for your answers

In the end, only the first one is useful. Is there a case where I might prefer the 2nd or 3rd solution over the first?

In fact, the 2nd solution will always be waiting for the end of execution, even if you set the option to call and forget

494167725_DynamiqueCalloptionx80.PNG.da66e8b28664f8fa41de9608227f9a83.PNG

 

FYI, there is a new feature in LabVIEW 2024Q1 where can wire the reference to the VI Path input on the Open VI Reference.  You do also need to wire up the Type Specifier if you need the strict type.  NI has stated the need for the type specifier  as a bug per this thread on the dark side: New Open VI Reference Functionality

Call Waits_BD.png

Edited by crossrulz
  • Thanks 1
Link to comment
16 hours ago, crossrulz said:

FYI, there is a new feature in LabVIEW 2014Q1 where can wire the reference to the VI Path input on the Open VI Reference.  You do also need to wire up the Type Specifier if you need the strict type.  NI has stated the need for the type specifier  as a bug per this thread on the dark side: New Open VI Reference Functionality

Call Waits_BD.png

Hello @crossrulz, I presume you meant to write 2024, not 2014.

For the moment we're stuck with the 2021 and 2022Q3 versions. We are not a fan of the subscription system. We find it relatively expensive (NI has made up for its hardware losses due to COVID on the software side), and we've never really had the information we needed to go the perpetual license route. We used to work directly with National Instrument, but now we have to go through a reseller. And I have to say that I have a lot of trouble with the reliability of the answers they give us. They're salesmen... 

We're a small special machines company, and there are mainly 2 of us working with labview. On the other hand, we need to activate a lot of licenses during development. There are several machines in the workshop at the same time, sometimes more than 10. The reseller told us we could only activate 3 PCs per license. We'd like to upgrade labview, but if I can't activate more than 3 machines at the same time, without having to pay for additional development licenses, it's not interesting for us.... 

Link to comment

Not having looked at the details of the code you have, here is a quick general comment:

If the dynamically called error monitor needs to close if the main VI closes I would not code that by having it monitor the boolean of the main (reading values using property nodes is not optimal in any case, globally or locally), but rather destroy the queue in main when it closes and then have the dynamic VI react to the queue erroring out, or use a dedicated user event, notifier or channel wire to message this (bidirectionally if needed).

(There are countless ways to do this, all with their pros and cons. A named "System" notifier e.g. that is used for any part of the application that needs to know when to gracefully shut down, reload setting etc. is *one* simple solution that allows anyone to monitor it without polling or having anything pre-wired (just mentioning one such solution here is opening up for a bunch of protests from people preferring other methods due to cons with this particular method, but anyway...))

Link to comment
22 hours ago, Mads said:

Not having looked at the details of the code you have, here is a quick general comment:

If the dynamically called error monitor needs to close if the main VI closes I would not code that by having it monitor the boolean of the main (reading values using property nodes is not optimal in any case, globally or locally), but rather destroy the queue in main when it closes and then have the dynamic VI react to the queue erroring out, or use a dedicated user event, notifier or channel wire to message this (bidirectionally if needed).

(There are countless ways to do this, all with their pros and cons. A named "System" notifier e.g. that is used for any part of the application that needs to know when to gracefully shut down, reload setting etc. is *one* simple solution that allows anyone to monitor it without polling or having anything pre-wired (just mentioning one such solution here is opening up for a bunch of protests from people preferring other methods due to cons with this particular method, but anyway...))

Hello @Mads

Thank you for your reply. I followed your advice. I destroyed the queue in the main VI, and used the error output from the state of this queue to terminate the dynamically called VI. It works fine, thank you 🙏. I hadn't thought of that 🙄.... 

do you know why I'm looking into : View=>Browse Relationships=> Reentrant items 

I see the number of VIs that I've actually called, in running. But sometimes I also see some that are stopped. Should I add a close reference at the end of the VI? Can a VI close its own reference? 

563848366_CloseRef.PNG.6788eb847c0f62ea2bd3d51912fe3c49.PNG

Link to comment

Here is a good thread that covers various related scenarios:

https://forums.ni.com/t5/LabVIEW/why-open-new-clone/td-p/2976973

Regarding the queue; if it is not in use anywhere (regular dequeue e.g.) so that the close can be detected there? If it is polled in the timeout you probably do not need to run that timeout every 10ms as that will put a high load on the CPU. For users to perceive things as "real-time"/instant anything below 300 ms or so will do.  You can also wire the error wire directly to the stop terminal unless you have other cases there that generate a boolean, then using the status alone is more practical..

Link to comment

Yes, I knew I could wire the error directly, but I have another condition with booleen. In the end, after thinking about it for a while, I don't really need it anymore, the queue state is enough for me. And it's also true that I'm not 10ms away from closing this sub-VI. Thanks for your advice

Link to comment

I use User Events as the transport mechanism between asynchronous processes.  As a result I wish there were a feature where there was an event generated when a reference goes invalid.  I made an Idea on the Idea Exchange here.  Similarly the work around is to have a timeout where the reference is checked to be invalid.  A better solution is to send a stop command as some kind of global user event, or in your case enqueue.  But as you've seen there can be edge cases where things stop unexpectedly and I just want all the running children to go through their cleanup process.  Stopping on the error, or invalid user event reference, is a fairly simple way to do that.

  • Thanks 1
Link to comment
On 3/5/2024 at 9:55 AM, crossrulz said:

FYI, there is a new feature in LabVIEW 2024Q1 where can wire the reference to the VI Path input on the Open VI Reference.  You do also need to wire up the Type Specifier if you need the strict type.  NI has stated the need for the type specifier  as a bug per this thread on the dark side: New Open VI Reference Functionality

Update:  There is now a 2024 Q1 patch that fixes this bug.  So you no longer need to wire up the Type Specifier when using the static VI reference wired to the VI Path input on the Open VI Reference.

The patch also covers several security issues.  Those who are using 2024Q1 really should go into NIPM and get the update.

Edited by crossrulz
Link to comment
On 3/11/2024 at 2:54 PM, hooovahh said:

I use User Events as the transport mechanism between asynchronous processes.  As a result I wish there were a feature where there was an event generated when a reference goes invalid.  I made an Idea on the Idea Exchange here.  Similarly the work around is to have a timeout where the reference is checked to be invalid.  A better solution is to send a stop command as some kind of global user event, or in your case enqueue.  But as you've seen there can be edge cases where things stop unexpectedly and I just want all the running children to go through their cleanup process.  Stopping on the error, or invalid user event reference, is a fairly simple way to do that.

It's a good idea ! 😊

Link to comment
  • 1 month later...
On 3/5/2024 at 5:40 AM, dadreamer said:

There's obscure "Run At Any Loop" option, being activated with this ini token:

showRunAtAnyLoopMenuItem=True

Does this token need to be added to the INI file of a compiled exe or does it automatically get included? 

Link to comment
4 hours ago, mcduff said:

Does this token need to be added to the INI file of a compiled exe or does it automatically get included? 

It's just a cosmetic token to get "Run At Any Loop" option visible in the IDE mode. After the flag is set, it's sticky to VIs, on which it was activated. No need to add the token to the EXE's settings.

  • Thanks 1
Link to comment

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.