PaulL Posted March 17, 2012 Report Share Posted March 17, 2012 OK, I have been struggling with this all day. I don't like the solutions I have found yet. Prior to today I had a top-level view (call it A) and it puts VIs (B0...n) in subpanels (and runs them dynamically). A has references to the B VIs, so when the user closed A it just aborted all the B VIs. That's a bit brute force, but it worked just fine. Today, I decided to put C in a subpanel of one of the B VIs. Starting up is not a problem and the code runs great, but shutting down the same way doesn't work since A doesn't have a reference to C (currently), so C continues running. That's not the plan. So, we could: Have B pass C's reference to A and A can shut down all parties. Have A tell B to shut down and B tell C to shut down. (Conceptually I like this much better.) Of course this means the abort mechanism won't work. Constraints: No ugliness! This means no polling (super yuck!). This should fit within the existing event structure approach. (So we can rule out global variables or single-process shared variables.) At each level the views must be able to operate stand-alone. For instance, B must be able to run without A (which was true before we added C, by the way). I have tried: Having each parent fire the FrontPanel close event on its children (FrontPanelClose? is not available via reference), but this doesn't work for subpanels (as I eventually found mentioned in other threads). Using a signaling event on a stopVI button for each VI. This works (or at least seemed to in a brief test) but it requires putting a control for this purpose on each VI. I don't like this because if I even double click on the terminal (even if the button is invisible) I have to spend time carefully putting the front panel back at its origin. More ugliness. Other ideas: We could have B pass C's reference to A, as stated above, but creating and then reading an indicator for this on B, while it would work, is quite messy. Creating a user event in A and handing this off to B. This will work but it requires some care to meet the second constraint, and it again requires adding control to each VI (or passing the event reference in some other fashion, but that doesn't provide any advantages over the control signalling method already tried). Use networked shared variables. I know this will work and we already have the mechanism in place. It is super-easy for us to implement. Moreover, we don't need to add any controls. On the other hand, in this particular circumstance I'd kind of like to avoid this because I don't really want to deploy any more libraries on the host computer. (Maybe I shouldn't worry about that.) Suggestions? Quote Link to comment
drjdpowell Posted March 17, 2012 Report Share Posted March 17, 2012 How do your B and C VIs communicate with the outside world? If I were doing something like this, each VI would have a queue (or similar) message receiving system and it would shutdown on receiving a “Shutdown” message or if it’s message queue becomes invalid. This makes full shutdown of everything quite easy. Quote Link to comment
Aristos Queue Posted March 17, 2012 Report Share Posted March 17, 2012 Neil: that's exactly what I would suggest -- with the option to replace "user event" with other com techs such as queues or notifiers, as needed in your code. Actor Framework would just make both the outer host VI and the inner subpanel VI be actors and then communicate the stop message through the queues. Quote Link to comment
drjdpowell Posted March 17, 2012 Report Share Posted March 17, 2012 If you have any communication method with the dynamically-launched VI (queues, notifier, etc.) you can create this reference in the calling VI. When the calling VI goes idle, this invalidates the comm reference, throwing an error (from dequeue) which can be used to gracefully shutdown. Alternately, one can programmatically release the reference. An advantage of this is that dynamically-launched processes will always shutdown gracefully, regardless of how the top-level VI exits (no orphaned processes left running in the background). I call these processes “autoshutdown slaves”. Unfortunately, one can only do this with User Events via polling (as an invalidated User Event doesn’t throw an error). I hide the polling in a background process that fires a second “shutdown” User Event, so at least it doesn’t look ugly. Quote Link to comment
PaulL Posted March 20, 2012 Author Report Share Posted March 20, 2012 Thank you for your prompt suggestions! Sorry for not replying on the thread sooner! I was out sick yesterday but I am happy to be fairly functional once again. On the suggestions: 1) Communications: We could extend our networked shared variable communications to do this (and use shared variable value change events), as I mentioned before, but I think there are two issues with this: a) We would be using networked shared variables for intraprocess communication. This is possible but seems inappropriate. b) Relatedly, this wouldn't scale well (at least not easily). We want each level to run stand-alone, and we must be able to reuse a subpanel in another view. If we use networked shared variables, to which variable do we subscribe? (This is one area where queues might have a slight advantage, but we have already committed to using events.) I can't think of any other purely event-driven approach (again, we are disallowing polling) that will fit the bill. Single top-level event: I like this (but with a tweak) except for one problem: 1) Tweak: Each level must be capable of creating the event because each must be able to be the top-level element. (I don't think this would be difficult to implement in some fashion.) 2) Problem: How does each level register for the user event? As far as I have worked this out I think to do this there must be a control on the front panel of the VI in the subpanel. I don't want to have such a control. (Maybe if a class does the work and handles control of the view front panel itself, though, that might be OK. Maybe that is what you are doing. I am having a somewhat difficult time envisioning how that will work with supanels, but maybe....) Can you clarify? One of my co-workers has implemented an XControl approach. We'll also look at that in a minute and see if it fills the need.... Quote Link to comment
PaulL Posted March 23, 2012 Author Report Share Posted March 23, 2012 OK, we thought a lot about this and we tried to implement something that adheres to the following principles: 1) The front panel of a the view the user sees, i.e., the VI that we put in the subpanel, should have no controls or indicators other than what the end user wants to see. 2) The view VI block diagram should be lightweight as well. 3) Communication, if any, should be self-contained and unambiguous. 4) The view may not run concurrently with the control component (ours don't, actually) so the view and all its components should be able to close based on a PanelClose? event on the top-level window VI. 5) Polling in a loop is not allowed. 6) Each view VI must run and stop correctly stand-alone or when called by another VI. It must be able to run as a top-level VI or inside a subpanel. We actually came up with two solutions that we think are satisfactory. We are not sure yet which we will use. One is mine. I attempted to implement something along the lines of the Composite Pattern. (Note that in the end I treated all existing elements as composites. I'm not sure what a leaf would be.) I am attaching a zip file of the concept code for those interested. I'd like some feedback. StoppingSubpanelsComposite.zip Open the Specific folder in the project and run viewMain. This shows we can open and close a view from a controller. Then run each view.vi in each of the View classes. They start and stop correctly. To create a new view we would copy a ViewX template and customize the view and init methods as needed. That's it. Unfortunately we need to specify the subpanel names in the init methods. (We can make the exact appearance different, but I don't see how to make this fundamentally simpler.) Presumably we could extend this pretty easily to add features if needed. I don't know of any bugs but this is just concept code. One of my colleagues developed an XControl approach. The XControl wraps the subpanel and of course runs in its own thread (note it is possible to do this without XControls) so there is no need for stop and start methods. I have a couple further comments: 1) I think something like this should be native to LabVIEW to simplify view development (and guide developers to build composite views). If you agree vote for my idea here: http://forums.ni.com...y/idi-p/1818645. (I see there are other similar suggestions, too.) 2) Another way to do this would be to generate a PanelClose? or equivalent (stop?) event via a reference to a VI running in a subpanel. Quote Link to comment
Yair Posted March 25, 2012 Report Share Posted March 25, 2012 I haven't looked at the code too closely, but here are some quick comments: You don't stop the VIs cleanly when they are in a subpanel. I don't like the Abort VI/Close FP method. How about creating a stop user event in ViewComponent:init.vi and then triggering it in ViewComponent:stop.vi? I haven't worked through all the potential race conditions, and it would require the view VI to be more complex, but it seems cleaner. Instead of entering the SP names in the init VI, how about moving this code out to the view VI and then simply give the start VI an array of VCs and a parallel array of SP references? Again, this would complicate the view VI, but it would make the code safer and more readable. This reminds me of what we played with here, although there it was inheritance - http://forums.ni.com/t5/LabVIEW/An-experiment-in-creating-compositable-user-interfaces-for/m-p/1262378#M529154 Note that AQ's implementation there is considerably more complex than what you probably need here. My code there is more in line with this, but it does automatic ordering of the front panel, which is probably not what you want. Quote Link to comment
PaulL Posted March 26, 2012 Author Report Share Posted March 26, 2012 Yair, 1) I agree. This is simply a (harmless in our case) workaround because we don't have access to the "Panel Close?" (which would be the ideal solution!!!!) or other such event for a VI in a subpanel. We would need a front panel control to implement a user event. 2) That is the way we had it originally, but if a VI in a subpanel is aborted it can't stop any VIs in its subpanels. This is a workaround necessitated by the decisions we made in step 1. (The XControl approach actually does not have quite the same problem.) 3) Thanks. I hadn't seen that link (or the links from that page). They are most interesting. In the end, I think there is no way in the present version of LabVIEW to do what we want in an ideal fashion (regrettably). As far as I can see the only options require a compromise. I think we can either 1) wrap the view VIs with something to shut them down (abort them) -- which is what I did in the code I attached and what my colleague did with the XControl; OR 2) put a control to pass a user event on the front panel of each view VI. I actually started such a thing last week (making the control small and invisible and putting it at the origin), but I decided I didn't like it and abandoned it. Maybe this is the more palatable compromise, though. I'm going to revisit it now. Quote Link to comment
drjdpowell Posted March 26, 2012 Report Share Posted March 26, 2012 In the end, I think there is no way in the present version of LabVIEW to do what we want in an ideal fashion (regrettably). As far as I can see the only options require a compromise. I think we can either 1) wrap the view VIs with something to shut them down (abort them) -- which is what I did in the code I attached and what my colleague did with the XControl; OR 2) put a control to pass a user event on the front panel of each view VI. I actually started such a thing last week (making the control small and invisible and putting it at the origin), but I decided I didn't like it and abandoned it. Maybe this is the more palatable compromise, though. I'm going to revisit it now. I go with (2), myself (you can see the hidden “Startup Message” in my code image above). However, there is also a third option: using a temporary named queue to do the necessary information passing. Use the VI name (or clone name) as part of the queue name to ensure it is unique. This gets around the need for a hidden control. Quote Link to comment
PaulL Posted March 26, 2012 Author Report Share Posted March 26, 2012 I go with (2), myself (you can see the hidden “Startup Message” in my code image above). However, there is also a third option: using a temporary named queue to do the necessary information passing. Use the VI name (or clone name) as part of the queue name to ensure it is unique. This gets around the need for a hidden control. Yes, we thought of the temporary named queue approach. It might work. In any case, I will see if I can get this to work if I pass the event reference by wire first. I'm working on it now.... Thanks for not giving up on this thread! Quote Link to comment
PaulL Posted March 26, 2012 Author Report Share Posted March 26, 2012 OK, here is a quick version with events. StoppingSubpanelsUserEvent.zip It really is what Neil suggested in the first place, I suppose. Quote Link to comment
PaulL Posted March 27, 2012 Author Report Share Posted March 27, 2012 So the previous version had a problem if we ran a high-level view VI (e.g., A), then ran one of its children (e.g., D) afterwards without closing the project. D still had the old value of the input wired so it thought the event was valid, but it wasn't. There are a fews way we thought of to deal with this. The simplest we considered was to add a timestamp when we created the event. If the timestamp isn't recent (presently hard-coded to 0.5 s, which handles all the use cases we expect we will encounter), then we treat the event as invalid and create a new one. I did some other clean-up in this version, but that's the major change. StoppingSubpanelsUserEvent2.zip Quote Link to comment
drjdpowell Posted March 27, 2012 Report Share Posted March 27, 2012 Haven’t studied your latest versions, but here’s something I whipped up quickly: SubView.zip It allows the launch of subViews where when the owning view goes idle it triggers a “Shutdown” User Event in the owned subView. The code in the subView is just a User Event control, while the code in the owning view is a single “Launch SubView” subVI with inputs for VI and sub panel refs: Internally, “Launch SubView” crates a queue and passes this, along with the VI and sub panel refs to a dynamically launched “SubView Helper” (shown below). SubView helper creates the “Shutdown” User Event and calls the subView VI and puts it in the sub panel.It then waits for the queue created in “Launch SubView” to go invalid (which happens when the owning view goes idle) and then fires the Shutdown event. This seems to work, shutting down all subViews when the owning view stops for any reason. I have one unresolved issue where the subViews remain reserved for execution while the owning View is still in memory. But the subViews do shut down. This is a pattern I call “autoshutdown slave”, where a dynamically launched process is tied to its launcher such that it will automatically shutdown if the launching VI hierarchy goes idle (stops) for any reason. The connection is made by a reference created in the launching hierarchy that goes invalid and throws an error in the launched process (a User Event going invalid doesn’t throw an error anywhere, so I had to use a queue instead, which makes this example more complex than otherwise). — James Quote Link to comment
PaulL Posted March 27, 2012 Author Report Share Posted March 27, 2012 James, Thanks for sharing! We took a close look at it, and observed the same issue. The queue idea is clever, though.... It does point out a potential issue with what I did. If you abort the top-level VI the subVIs still run (in the development environment). I'm not sure that's a problem for us. Paul Quote Link to comment
mike_spacex Posted March 27, 2012 Report Share Posted March 27, 2012 James, The "unresolved issue" can be fixed as follows: Change the 'View A' and 'View B' static VI references to NOT strictly typed. In 'SubView Helper.vi', instead of the 'call by reference node', use 'Control Value.Set' invoke node to pass the 'Shutdown Event' then run it with 'Run VI' invoke node with 'Wait Until Done' set to TRUE. By not requiring a strict VI reference to the 'Launch SubView' VI, you also gain some flexilbity in what VI's could be used since there's no more tie to terminal pane configuration. 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.