LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Call and Forget and Notifier Scope

Solved!
Go to solution

Hey,

 

i'm trying to build an application on the assumption that a notifier always stays in memory/is accessible as long as the root vi (or any other called subvi) in the same scope is active.

 

I assembled a small example in the attachment to convey my contrary observation - this contains

 

Async_Caller: Just calling a SubVI asynchronously and checking a notifier some time later for state information, the root vi in this context

Callee: sub process - in this case failing with a random error directly after the call (in the actual use case, this is a sub-process running indefinitely when no error occours) 

FGV: stores the reference for the notifier - also obtains the notifier upon init action 

 

Async_Caller fails with "Invalid Refnum", so the notifier got out of scope when callee died, as far as I can see this is a result of the option "Call and forget" (I did not assume that it means forgetting everything after the call). This behavior changes when I set the option to "Prepare to call and collect". But I do not want to collect with "Wait On Asynchronous Call" node, as the callee may run indefinitely and will be stopped by other means eventually.

The help file discourages using option 0x100 in this context but 0x80 is also not working.

What is the right approach? Shouldn't the notifier stay in memory even with 0x80?

0 Kudos
Message 1 of 10
(613 Views)

 "Call and forget" and "Prepare to call and collect" have the same behavior. The notifier (and all references) created in the callee are invalidated the moment the callee stops.

 

The difference is that with call and collect it lives long enough to not get an error. If you'd actually wait and collect, after that the notifier doesn't live anymore either. Not collecting might keep the Callee from stopping, and thus the TLDS from stopping, and thus keeps the reference alive. This could also be a simple race condition, the callee lives long enough, and the FGV is read before it stopped.

 

Why not initialize the FGV in Async_Caller.vi?

 

Better yet, create a notifier (in Async_Caller.vi), and pass the reference to (dynamically started) VIs. LabVIEW does work best when you work by wire. No need for globals.

 

0 Kudos
Message 2 of 10
(585 Views)

 


wiebe@CARYA wrote:

 "Call and forget" and "Prepare to call and collect" have the same behavior.


as with my example, no, they do not.
0x80 -> Invalid Refnum
0x100 -> works

Callee stops executing in both cases immediately. just the wait(ms) keeps Async_Caller.vi open for longer.

 

The callee stops, but the callchain also includes the root vi on top which afaik means all other called (and maybe ended) VIs stay in memory. This is also shown in on the  Frontpanel of the callee as the run arrow is in reserved state.


wiebe@CARYA wrote:

 

Why not initialize the FGV in Async_Caller.vi?

 


Then the behavior just reverts. Now callee loses the memory instance when it lives longer than Async_Caller. Invalid refnum once again.


wiebe@CARYA wrote:

 

Better yet, create a notifier (in Async_Caller.vi), and pass the reference to (dynamically started) VIs.

I'm passing the reference to callee and async_caller. The problem is my instance of this reference dies 😕

 

This feels counter intuitive to my previous labview experiences.

0 Kudos
Message 3 of 10
(460 Views)

  

0 Kudos
Message 4 of 10
(560 Views)

wiebe@CARYA wrote:

 "Call and forget" and "Prepare to call and collect" have the same behavior.

 


As with this example, no, they do not:
0x80 - invalid refnum
0x100 - works
In both cases the callee pretty much stops immediately. Only Async_Caller stays open for longer through wait(ms) node. Also during Async_Caller beeing executing, Callees' FP is indicated to be reserved (arrow within arrow) which i assumed to also include a still active memory instance.


wiebe@CARYA wrote:

 

Why not initialize the FGV in Async_Caller.vi?

 


Than the behavior just reverts. If Callee lives longer than Async_Caller, the refnum becomes invalid again.


wiebe@CARYA wrote:

 

Better yet, create a notifier (in Async_Caller.vi), and pass the reference to (dynamically started) VIs. LabVIEW does work best when you work by wire. No need for globals.

 


I'm just passing references here - imho the problem is the instance beeing lost.
So is this to be expected by using Option 0x80?

Upon further investigation i cannot use 0x100 because when Async_Caller goes out of scope, Callee is aborted automatically 😞
 

0 Kudos
Message 5 of 10
(564 Views)

@Moray2000 wrote:

wiebe@CARYA wrote:

 "Call and forget" and "Prepare to call and collect" have the same behavior.

 


As with this example, no, they do not:
0x80 - invalid refnum
0x100 - works
In both cases the callee pretty much stops immediately. Only Async_Caller stays open for longer through wait(ms) node. Also during Async_Caller beeing executing, Callees' FP is indicated to be reserved (arrow within arrow) which i assumed to also include a still active memory instance.



0x100 only works because Async_Caller waits. If you add the wait for async, you'll see that the notifier isn't valid anymore.

 


@Moray2000 wrote:


wiebe@CARYA wrote:

 

Why not initialize the FGV in Async_Caller.vi?

 


Than the behavior just reverts. If Callee lives longer than Async_Caller, the refnum becomes invalid again.


So if the intent of the notifier is used by the Asyn_Caller, that doesn't really matter.

 

If the notifier is used on a larger scope, initialize the notifier in that scope, and pass the reference.

 

If you really, really want anybody to initialize a notifier (or other reference), you'd have to dynamically start a VI that creates the reference, and then keep the VI running. The only problem with this is that the Vi will keep on running, even if you close your project or LabVIEW, so you'll get weirdness.

 


@Moray2000 wrote:

wiebe@CARYA wrote:

Better yet, create a notifier (in Async_Caller.vi), and pass the reference to (dynamically started) VIs. LabVIEW does work best when you work by wire. No need for globals.


I'm just passing references here - imho the problem is the instance beeing lost.
So is this to be expected by using Option 0x80?


References are expected to become invalid when TLDS stop. Which is what happens with option 0x80 (and 0x8 and (pretty sure, but irrelevant,) 0x100).

 

This is by design, and usually it's good.

 

It probably won't change either. I tried to make this an option or to have more control over this, but it seems it just won't happen.

0 Kudos
Message 6 of 10
(550 Views)

@wiebe@CARYA
please elaborate what you mean with TLDS - just assuming you mean the root/top level vi of the callchain


wiebe@CARYA wrote:


References are expected to become invalid when TLDS stop.

 


I fully agree. But in this case my Top Level VI does not stop, Async_Caller is active for some ms after Callee stopped already. Callee (i.e. the FGV SubVI) was responsible for creating a notifier instance in memory, but it is destroyed after Callee stopps, not after the original caller stopps.

Would i have started Callee in an ordinary way by just putting it in a parallel branch on the block diagram, the notifier would be alive along the lifetime of the TopLevel Vi.

To conclude: asynchronous call with option 0x80 creates a new parallel Callchain with a new TopLevel VI (Callee in this case) and automatically cleans up when this instance dies?  

...other elements of FGV (the values stored in the shift register itself) survive this. Isn't this inconsistent behaviour?

0 Kudos
Message 7 of 10
(545 Views)
Solution
Accepted by topic author Moray2000

@Moray2000 wrote:

@wiebe@CARYA
please elaborate what you mean with TLDS - just assuming you mean the root/top level vi of the callchain


The top level data space.

 

Note that a VI that is started dynamically, is a new TLDS.

 


@Moray2000 wrote:

@wiebe@CARYA


I fully agree. But in this case my Top Level VI does not stop, Async_Caller is active for some ms after Callee stopped already. Callee (i.e. the FGV SubVI) was responsible for creating a notifier instance in memory, but it is destroyed after Callee stopps, not after the original caller stopps.

Would i have started Callee in an ordinary way by just putting it in a parallel branch on the block diagram, the notifier would be alive along the lifetime of the TopLevel Vi.

To conclude: asynchronous call with option 0x80 creates a new parallel Callchain with a new TopLevel VI (Callee in this case) and automatically cleans up when this instance dies?  


Yes, a dynamically started VI is a new TLDS.

 

This makes sense, as the dynamically started VI  can keep running when the starting VI stops.

 


@Moray2000 wrote:

...other elements of FGV (the values stored in the shift register itself) survive this. Isn't this inconsistent behaviour?


Referenced objects are created and destroyed in the top level dataspace.

 

The values of the references still live on, like all data. It's just that the objects they refer to don't exist anymore.

 

In that sense, it is consistent. It's just that references are the only data types that refer to objects (that are destroyed).

0 Kudos
Message 8 of 10
(535 Views)

wiebe@CARYA wrote:


Yes, a dynamically started VI is a new TLDS.

 

Thanks for that information - this explains it pretty much

 

wiebe@CARYA wrote:


Referenced objects are created and destroyed in the top level dataspace.

 

The values of the references still live on, like all data. 

 


I do not really like this distinction 😉 - the FGV kind of traverses both data spaces, or has its own with the uninitalized shift register, except for the referenced objects. Isn't the FGV the owner of these objects?

 

Nonetheless i will set your reply as answer, thanks.

0 Kudos
Message 9 of 10
(530 Views)

@Moray2000 wrote:
wiebe@CARYA wrote:


Referenced objects are created and destroyed in the top level dataspace.

 

The values of the references still live on, like all data. 


I do not really like this distinction 😉 - the FGV kind of traverses both data spaces, or has its own with the uninitalized shift register, except for the referenced objects. Isn't the FGV the owner of these objects?

 

Nonetheless i will set your reply as answer, thanks.


The FGV holds the values, for references just like other data types. A probe will show a reference value (and probably mentions it's not valid anymore).

 

The object that it's referring to is owned by the top level data space where it was created. So if the FGV creates the object in TLDS Callee.vi, the object is destroyed when Callee.vi stops.

 

I do remember getting burned by this. And I wasn't a complete beginner. I knew the theory, but in cases like this it can be puzzling. After one or two times getting burned, you intuitively learn to avoid it, or at least I did. I had VIs that started each other sequential, in a sub panel. Worked well, until A.vi opened a file reference, passing it to B.vi and then stopped...

 

Here's an idea that applies to Persistent Data Value Reference (DVR) - NI Community, but it's implied that all references could use this. The OP refers to the old idea (that I posted).

0 Kudos
Message 10 of 10
(510 Views)