mje Posted August 3, 2011 Report Share Posted August 3, 2011 OK, so I'm very excited about the Start Asynchronous Call primitive in the new LabVIEW 2011. Awesome stuff. Went ahead and started using it in several libraries I have where I used to use the old kludge method to do it. Works fantastically. But...I don't really like the way it was implemented with regard to reentrancy. I have a use case where I have a set of re-entrant VIs I open and start asynchronously, then at any given time I'll be placing one of them in a sub panel depending on context. Works beautifully with the old method, because I call Open VI Reference with the 0x8 option to get a reference to the specific clone, and can plop it in the sub panel whenever I wish. But things don't quite work that way with the new way of doing things. When I call Open VI Reference, I need to use the 0x40 option to allow simultaneous calls to the reentrant VI which opens a refnum to the VI, but as the documentation states: ...If you set the 0x40 option flag when you open a reference to a target VI, the Start Asynchronous Call node starts a call to a clone of the referenced VI, not to the referenced VI itself... So I can't use this reference to place the VI in a sub panel, I instead need to get creative and use some form of synchronization to get back a refnum to the running VI, etc. Bah, what should have been easy has now been made complicated. Sigh... Attached is a two VI example showing the (as expected) non-functioning behavior: Async Subpanel.zip This seems all related to the way the Wait On Asynchronous Call primitive works, in that when you have multiple clones of a VI running, the sequence with which the clones returns does not matter with respect to the sequence of blocked wait calls, which allows code like the following to work: Anyways, it would be really nice if there was some way for the Start call to return a refnum to the VI that's actually running. I've got to say I really don't understand the decision to have the methods work like this. I see where you were going with the design, understand how it works now, and even can see some use cases, but why engineer a new way of working with clones like this when you already had a functioning option (0x8). Surely there's not an architectural reason that would keep LabVIEW from blocking until a specific clone returns had the 0x8 option been enabled for asynchronous calls? Hope you all had a great NI Week, wish I had been there. Regards, -michael Quote Link to comment
Aristos Queue Posted August 5, 2011 Report Share Posted August 5, 2011 Both systems -- to wait for a specific clone or to wait for any arbitrary clone -- are possible. Here's how to do the "wait for a specific clone." Save both of these VIs to the same directory, then run Caller2.vi. That will launch three copies of the async VI. No matter which order you click stop on those three copies, you'll always get the result "0, 1, 2" in the final array because they're collected in order. Note that this example uses the 0x8 flag -- you were wondering why there was a new flag... it's to support the other use case where you don't care about the order. Caller2.vi stop on button.vi I've got to say I really don't understand the decision to have the methods work like this. The case when you don't care which instance you get back is when the output of the instance tells you what position in the final output that instance has. Think of an autoindexing output tunnel on the parallel For Loop -- it runs a whole bunch of frames in order, and then puts the outputs into a single array. Each parallel instance knows where in the final array to end up, so it doesn't matter which one finishes first and copies its results into the final array. There are many use cases where that's useful with spawning multiple copies of the Asynch Call By Ref node and then catching them in whatever order they finish. Quote Link to comment
mje Posted August 5, 2011 Author Report Share Posted August 5, 2011 Strange. The Open VI Reference documentation clearly states for both the 0x80 and 0x100 flag: "Do not use this option flag with 0x08," and in fact one of the first things I tried was to use it anyway. My efforts were rewarded with some error along the lines of "The referenced VI is not in a state compatible with this operation", or something similar. Is the documentation out of date? If so, then the 0x40 flag makes sense since we can choose between the two methods. My criticism was aimed at least initially it looks like you went ahead and replaced the 0x8 option with 0x40 for asynchronous calls. Having both options open is an excellent decision, if indeed the 0x8 one is stable. Quote Link to comment
mje Posted August 5, 2011 Author Report Share Posted August 5, 2011 Edit: I went back to my use case and tried using the 0x108 option again and it worked. The error I was receiving was actually due to something unrelated to the async call. When it didn't work and the documentation said it shouldn't, I didn't even try to fix it. Quote Link to comment
Aristos Queue Posted August 5, 2011 Report Share Posted August 5, 2011 Hm... In this case, I'm a user as much as you are, and I didn't see that note, so I just assumed the 0x108 would work... and it seems to do so. I will see if I can get one of the developers to chime in. Quote Link to comment
JasonC Posted August 5, 2011 Report Share Posted August 5, 2011 You should not use option 0x8 with option 0x80 or 0x100. Or, more generally, you should not use option 0x8 anytime you are opening a strict VI reference. When opening a strict VI reference, a reentrant instance is returned automatically so 0x8 is pointless (and harmless). The 0x8 option is really only useful when used in conjunction with the Run VI method. There were two problems with the original Main.vi from mje. Issue 1: Option 0x40 was passed in. This option works for both the Async CBR and the normal CBR in a similar way. Passing 0x40 makes the reference returned be to the actual target VI and not a clone of the target VI. Then, when you perform a CBR or a Start Async Call, you actually call a clone. This can cause issues when doing things like showing a FP or embedding it into a subVI. The called VI is not the same as the VI reference. When opeing a VI reference, if you do not pass in option 0x40 and you are opening a strict reference and the target VI is reentrant, the reference returned will be to a clone VI. This works the same whether or not 0x100 is passed in. Issue 2: The Start Async Call happend before inserting the VI reference into the sub panel. In this case, the asynchronously run VI runs to completion before being inserted into the sub panel. Inserting the sub panel then loads the FP of the target VI. Since the VI already ran, we end up with the default data and we end up seeing a message saying the VI had not run. So, if you insert into the sub panel first, the FP will be loaded. Then, when you start an async call, the results will be remembered by the FP. I attached a new version of Main.vi that works. More Info on Option 0x40: Option 0x40 allows multiple synchronous calls with one reference. ie: You open one reference to a reentrant VI with option 0x40. You then branch the wire and wire it to two CBR nodes. Each CBR node can execute a different reentrant instance of the target VI at the same time. If 0x40 was not passed, one CBR would run while the other blocked until it finished. It works the same for the Async CBR other than the fact on the "Wait On Async Call" works. The Wait will return one of the calls that finished for that VI reference, but you do not necessarily know which one. I attached "Reentrant.vi" and "Option0x40.vi" to demonstrate option 0x40. Main.vi Reentrant.vi Option0x40.vi Quote Link to comment
mje Posted August 5, 2011 Author Report Share Posted August 5, 2011 Fascinating. I do like that 0x40 works with the traditional CBR node as well, it's a very useful behavior. The Start Async Call happend before inserting the VI reference into the sub panel. In this case, the asynchronously run VI runs to completion before being inserted into the sub panel. Inserting the sub panel then loads the FP of the target VI. Since the VI already ran, we end up with the default data and we end up seeing a message saying the VI had not run. So, if you insert into the sub panel first, the FP will be loaded. Then, when you start an async call, the results will be remembered by the FP. I attached a new version of Main.vi that works. Now that is very interesting, your example does work as advertised. What puzzles me though is if I modify Sub Panel.vi to have a one second wait in the VI, thus forcing it to not return until after the Insert VI call is made, I see what appears to be the FP of the target VI not the clone. However if I switch the order of execution of the insert and start nodes, I get the clone in the sub panel. The two VIs are attached: You can easily switch execution order via the enumeration on the FP of Main.vi. What might be happening here? The Open VI Reference (0x100) does indeed return seem to return a clone refnum: if the refnum is inserted into the sub panel before anything else is done to it, we observe the clone behavior. If Start Asynchronous Call is called before Insert VI we instead seem to observe the behavior of the target (not the clone). The refnums themselves don't seem to be changing. Something about that refnum seems to be mutating through the Start Asynchronous Call node, the behavior is not consistent when the Start and Insert node orders are reversed. Posted the wrong VIs, server seems to be returning errors when I try to edit my post: Main.vi Sub Panel.vi Quote Link to comment
JasonC Posted August 5, 2011 Report Share Posted August 5, 2011 If Start Asynchronous Call is called before Insert VI we instead seem to observe the behavior of the target (not the clone). I attached a new version of your sub panel VI that waits before writing to the string indicator. In this example, the sub panel says the target VI ran (after a second) no matter what you set the order of execution to be. In your original code, the front panel of the sub panel VI is not loaded until you insert the ref. Since the FP is not loaded, writing to an indicator during execution does not actually update the visible string on the FP. Then, when the FP is loaded, the string indicator gets the default data and not the data from the last time the indicator was written to. Sub Panel.vi Quote Link to comment
mje Posted August 5, 2011 Author Report Share Posted August 5, 2011 In your original code, the front panel of the sub panel VI is not loaded until you insert the ref. Since the FP is not loaded, writing to an indicator during execution does not actually update the visible string on the FP... Ah yes, that makes sense. Thank you so much for talking me through this! Now please correct me if I'm wrong, since 0x40 option will always return a refnum to the target (not a clone), if we need to obtain refnums to specific reentrant clones when using the 0x80 or 0x100 options, the only way to do so is to have the clone return a refnum of itself to the caller after it has been started (via a notfier or something). The 0x8 option seems to work, but we "should not" use it? -michael Quote Link to comment
JasonC Posted August 5, 2011 Report Share Posted August 5, 2011 Now please correct me if I'm wrong, since 0x40 option will always return a refnum to the target (not a clone), if we need to obtain refnums to specific reentrant clones when using the 0x80 or 0x100 options, the only way to do so is to have the clone return a refnum of itself to the caller after it has been started (via a notfier or something). Correct. Hopefully, you will not actually need to do this. I hope that the target VI itself could do whatever work needs to be done with the reference (like show the FP). But if you really need a reference to the actual clone, the target VI needs to pass it back to the calling VI in someway. On a similar note, if you need to match a Start node with a Wait node, you have two options: 1) Open a VI reference for each pair of Start/Wait nodes 2) Return something from the target VI that can be used to match a Start and Wait. ex: Passing a unique integer (like a loop index) into and out of the target VI The 0x8 option seems to work, but we "should not" use it? I'm suprised this works. I would have expected the 0x8 to have no affect. Quote Link to comment
mje Posted August 5, 2011 Author Report Share Posted August 5, 2011 Correct. Hopefully, you will not actually need to do this. I hope that the target VI itself could do whatever work needs to be done with the reference (like show the FP). I do have a case where it would be useful (though not necessary), but as always, there are many ways to skin this animal. I have my own configuration dialog framework, not unlike the one used in various places in LabVIEW. The caveat being the individual category VIs are all reentrant. Basic use is: A list of categories are supplied in the form of an array of VI paths, array of category names, and an optional array of configuration parameters. Each category's VI is started up but remain hidden, the appropriate configuration parameter is passed to each VI. Note multiple clones of the same VI might be presented as distinct categories. As the user clicks each category, the clone for the proper category is displayed in a subpanel. Currently I have the responsibility of switching what's in the subpanel in the main dialog since it owns the subpanel, but this could just as easily be delegated to the clone VIs by passing in a refnum to the subpanel during some activation event. When the dialog is dismissed, the return values for each category are collected and returned to the calling VI. If I go with the 0x140 option, like you said as long as I pass an index or something I can always sort out which VI is returning with each blocked wait call. It's a useful framework, if there's interest I'll post it once I finish reworking it. Quote Link to comment
John Lokanis Posted August 5, 2011 Report Share Posted August 5, 2011 I have a slightly different question about the CBR node. If I want the VI to run and dispose of it's own reference, how do I tell it to do that (I will not be calling the wait node since my VI returns its data via a queue). thanks, -John Quote Link to comment
mje Posted August 5, 2011 Author Report Share Posted August 5, 2011 In that case you just close the refnum after you make the start async call. I believe passing off a secondary reference to the asynchronous VI is handled automatically, I have at least confirmed closing the refnum you have access to does not cause the VI to return. Quote Link to comment
JasonC Posted August 8, 2011 Report Share Posted August 8, 2011 If I want the VI to run and dispose of it's own reference, how do I tell it to do that (I will not be calling the wait node since my VI returns its data via a queue). When you open the VI reference, the 0x80 and 0x100 options specify different lifetimes for the target VI: 0x80 -- Target VI lifetime independendent of the calling VI. ie: Closing the reference will not abort the target VI. The target VI will stay in memory until it finishes. 0x100 -- Target VI lifetime dependent on the calling VI. ie: Closing the reference will abort the target VI. If the calling VI runs to completion, the target VI reference will automatically be closed and the target VI will abort. Quote Link to comment
Aristos Queue Posted August 8, 2011 Report Share Posted August 8, 2011 0x80 -- Target VI lifetime independendent of the calling VI. ie: Closing the reference will not abort the target VI. The target VI will stay in memory until it finishes. I assume the caller should close the VI RefNum after calling Start so that the launched VI doesn't stay open. Yes? Quote Link to comment
JasonC Posted August 8, 2011 Report Share Posted August 8, 2011 I assume the caller should close the VI RefNum after calling Start so that the launched VI doesn't stay open. Yes? Yes, the user should close the refnum when they are done with it. The reference is not necessary to let the target VI run to completion, so, unless the reference is actually needed later, it should be closed. Quote Link to comment
John Lokanis Posted August 8, 2011 Report Share Posted August 8, 2011 Thanks guys! I use this 'fire and forget' method in a lot of my code. This new node will certainly help clean my diagrams up! Quote Link to comment
Aristos Queue Posted August 9, 2011 Report Share Posted August 9, 2011 In that case you just close the refnum after you make the start async call. I believe passing off a secondary reference to the asynchronous VI is handled automatically, I have at least confirmed closing the refnum you have access to does not cause the VI to return. I discussed this point further with JCase: The behavior of the Start Asynch Call By Ref node is identical to the Run VI method when you pass true for the "autodispose reference" parameter, with one minor exception. With Run VI, if you proactively call Close Reference, then the other VI will quit unless the VI has some other reason to stay in memory (another reference has been created or the panel is open). With SACBR, if you close the reference, it has no effect on the running VI. Quote Link to comment
JasonC Posted August 9, 2011 Report Share Posted August 9, 2011 With SACBR, if you close the reference, it has no effect on the running VI. One more thing...if you close the reference, the VI run by an async CBR or a normal CBR will leave memory when the execution completes (assuming there was nothing else keeping the VI in memory). Quote Link to comment
Orion Posted August 25, 2011 Report Share Posted August 25, 2011 I am trying to use similar pieces to what have been mentioned so far. However, I need to be able to spawn VI clones of several different VIs that have different connector panes from each other (different inputs, but same outputs) to be run in subpanels, and then read the outputs from these clones. I am using LabVIEW OOP. Each class has a dynamic dispatch method VI used to launch clones of its own static display method VI which is inserted into a subpanel. I thought that I could use a class property to store the dynamic strict VI reference, but as of LabVIEW 2010, it appears that can no longer be done. My thinking was that I could have a dynamic dispatch method for each class that uses the Wait for Asynchronous Call function and takes in the strict VI reference property of the class object and passes out the common outputs. The problem I run into is that I can't get the dynamic strict VI references from the VI where I launch the clones to the VI where I read the outputs since they are all unique. Right now, I am just writing the two outputs that I need from each clone to queues (the order that I receive the outputs does not matter), but I thought it might be more advantageous to be able to wire this data straight out of the connector panes. Quote Link to comment
Francois Normandin Posted August 25, 2011 Report Share Posted August 25, 2011 I am trying to use similar pieces to what have been mentioned so far. However, I need to be able to spawn VI clones of several different VIs that have different connector panes from each other (different inputs, but same outputs) to be run in subpanels, and then read the outputs from these clones. I played with exactly what you describe when the new LV2011 was launched. However, I decided to implement an event callback instead of reading results with the Asynchronous Call function. I used my Dynamic Dispatched method to make sure that all children clones received the event reference to notify the caller of the results. If you need the clones to send different data, make your event type be of a common ancestor to all these types and your caller can deal with each answer in a different way as it sees fit. Quote Link to comment
Aristos Queue Posted August 28, 2011 Report Share Posted August 28, 2011 You're not going to like my solution... it's icky, and I wish there was a better solution, but I've used this and it works: In your class, store a NON-strict VI reference. When you want to use the reference, use a property node to get the VI Name property and wire that to an Open VI Reference node, then take the output of that and use it for your Asynch Call By Ref and your subpanel. You can make this a bit more performant by storing a string alongside the VI reference that is the fully qualified name of the referenced VI so you don't have to use the property node every time. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.