John Lokanis Posted September 3, 2008 Report Share Posted September 3, 2008 NI has stated that you should not use the shared clones reentrant type if your VI has uninitialized shift registers (Functional Global). This is because the data space is shared between all instances of the VI so state cannot be maintained. My question is, what about consumers that have uninitialized shift registers? Since these VIs stay in memory and are running continuously, shouldn't they be immune to this problem? Can I have many instaces of this reentrant VI all running at once, without any data loss/corruption as long as they are all actively running (and waiting for their queue to feed them the next command?) I think this should work, but since I am seeing some strange behaviors, it would be good to get some second opinions. Thanks, -John Quote Link to comment
Yair Posted September 3, 2008 Report Share Posted September 3, 2008 That sounds like a reasonable assessment, although to be sure, you should set the preallocate option. Quoting from the help: QUOTE When you select the Share clones between instances option, LabVIEW does not create the clone VI until a VI makes a call to the reentrant VI. With this option, LabVIEW creates the clone VIs on demand, potentially introducing jitter into the execution of the VI. LabVIEW does not preserve state information across calls to the reentrant VI. This seems to indicate that the clone is created when you call the VI and since the VI doesn't stop, the clone should remain as a "separate VI". What issues are you seeing exactly? Quote Link to comment
ragglefrock Posted September 3, 2008 Report Share Posted September 3, 2008 QUOTE (jlokanis @ Sep 2 2008, 03:01 PM) NI has stated that you should not use the shared clones reentrant type if your VI has uninitialized shift registers (Functional Global). This is because the data space is shared between all instances of the VI so state cannot be maintained.My question is, what about consumers that have uninitialized shift registers? Since these VIs stay in memory and are running continuously, shouldn't they be immune to this problem? Can I have many instaces of this reentrant VI all running at once, without any data loss/corruption as long as they are all actively running (and waiting for their queue to feed them the next command?) I think this should work, but since I am seeing some strange behaviors, it would be good to get some second opinions. Thanks, -John Here's the reasoning behind shared clones not having uninitialized shift registers. The problem isn't that they share a data space. Each clone will get its own data space, just like any other reentrant VI. The problem is that it's usually impossible to safely predict which clone each specific subVI call will use. It might not be the same clone you used last time for that specific subVI call on your diagram. So the data space you use with the data from the uninitialized shift registers is not guaranteed to be the same data that subVI call set last time. You are sort of correct in saying this is less of a problem because your subVI calls don't ever end, but go on forever (to some extent). So you don't really care about which clone's data space you get "next time," since there probably isn't a next time. But that brings up this question: why have uninitialized shift registers at all for a VI call that runs only once and doesn't ever stop? Why does that help you? It sounds like you might as well have initialized shift registers to maintain the data while that subVI call is in place, but not necessarily to save it for the future. Quote Link to comment
John Lokanis Posted September 3, 2008 Author Report Share Posted September 3, 2008 QUOTE (ragglefrock @ Sep 2 2008, 02:29 PM) It sounds like you might as well have initialized shift registers to maintain the data while that subVI call is in place, but not necessarily to save it for the future. Yes, in most cases I do have initialzed SRs that contain data passed from one execution of the loop to the next (consumer structure). There are a few cases where the code in one case generates a reference that is passed to the next execution of the loop. In those cases, the SR contains meaningless data until the case that populates it executes. After that, the SR has a valid refnum. This is hte one where I did not intialize the refnum. So, I suppose I could initialize it with a void refnum (in this case a queue) but I figured that would not serve any purpose other than clarity. So, it sounds like I don't need to worry about data between loop executions even if I have 100's of instances of this reetnrat VI. They should all play nice and not step on each other's data. Back the the drawing board... Quote Link to comment
jdunham Posted September 3, 2008 Report Share Posted September 3, 2008 QUOTE (jlokanis @ Sep 2 2008, 01:01 PM) NI has stated that you should not use the shared clones reentrant type if your VI has uninitialized shift registers (Functional Global). This is because the data space is shared between all instances of the VI so state cannot be maintained.My question is, what about consumers that have uninitialized shift registers? Since these VIs stay in memory and are running continuously, shouldn't they be immune to this problem? Can I have many instaces of this reentrant VI all running at once, without any data loss/corruption as long as they are all actively running (and waiting for their queue to feed them the next command?) I think this should work, but since I am seeing some strange behaviors, it would be good to get some second opinions. Thanks, -John Disclaimer: it's quite possible I don't know what I'm talking about. I'm just guessing based on experience and the minimal documentation provided. I think it's misleadingto say "the data space is shared". It may be more helpful to say "the data space may be recycled" between your instances. Running Labview VIs can't share a data space period, otherwise the data in the wires would get mixed up. If your vi is not reentrant, then there is just one data space, but calls to the VI will be blocking so that the data space is not shared. (I'm sure you know this) So if it's reentrant, then the safest thing to do is manufacture a new data space for each instance of the reentrant VI, since the instances can run in parallel. I think this is how LV used to work before this option was introduced. The drawback is that if you call the reentrant VI from 10,000 clones of the same VI, you would need 10,000 data spaces, and you might have a memory problem. If your system is such that only a couple of these are actually invoked in parallel, and you don't care about preserving state (USRs), then you would want LabVIEW to recycle the data spaces. However, if you start to invoke the VI,and all of the existing copies of the data space are in use, then LV will have to make a new data space right then and there, and that will introduce jitter. If timing is much more important than memory use, or if you are using LV tricks to remember state across calls, then you want to pre-allocate. I would imagine you would want this most of the time, so that the USRs that we're all addicted to will just work like always. But if your application design is such that preallocating clones is a huge waste of memory, it's nice to have this directive where the programmer can promise LabVIEW that the VI won't be relying on saved state, and in return LV will try to reuse any existing data spaces which have not yet been garbage collected. I'm guessing these checkboxes were was added because somebody designed some application and it was a huge memory hog, and it turned out that it was a side-effect of LV assuming that data spaces should never be recycled. EDIT: I was too slow! Quote Link to comment
John Lokanis Posted September 4, 2008 Author Report Share Posted September 4, 2008 QUOTE (jdunham @ Sep 2 2008, 02:49 PM) if your application design is such that preallocating clones is a huge waste of memory yes. that is the case. And I do not rely on any states of USRs. Instead, I use SEQs (single element queues) to save and recall states between parallel processes within my code. I am essentially treating these SEQs as dynamic memory pointers. In my case, I launch many copies of the same VIT that call many reentrant VIs (all set to shared clones) that in turn create their own SEQs and pass them around to communicate between my producer and multiple consumers (7, in fact). So, if I was to preallocate, my memory usage would be through the roof (as it was before the shared close feature was added). Quote Link to comment
jdunham Posted September 4, 2008 Report Share Posted September 4, 2008 QUOTE (jlokanis @ Sep 2 2008, 04:11 PM) In my case, I launch many copies of the same VIT that call many reentrant VIs (all set to shared clones) that in turn create their own SEQs and pass them around to communicate between my producer and multiple consumers (7, in fact). So, if I was to preallocate, my memory usage would be through the roof (as it was before the shared close feature was added). Is there something special about using VI Templates? Nowadays you can just launch clones of a normal reentrant VI, without any copying, by passing option 8 into the Open VI Reference function. How are the queues 'passed around'? I think you said you used unnamed queues, but then it's not clear how that fits in with your cloning (not that we really need to know, but it may shed some light on your issue). Quote Link to comment
John Lokanis Posted September 5, 2008 Author Report Share Posted September 5, 2008 QUOTE (jdunham @ Sep 2 2008, 05:07 PM) Is there something special about using VI Templates? Nowadays you can just launch clones of a normal reentrant VI, without any copying, by passing option 8 into the Open VI Reference function. How are the queues 'passed around'? I think you said you used unnamed queues, but then it's not clear how that fits in with your cloning (not that we really need to know, but it may shed some light on your issue). Yes, there is one thing very special about VITs vs reentrant clones. A VI spawned (and detached from the caller) using a VIT can run in the background and have it's FP displayed in a sub-panel and removed while it is running. A reentrant VI must be set to hidden FP in order to get it to run detached from the caller, but then it cannot be displayed in a sub-panel because it's FP is considered 'open'. So, if you want to spawn daemons with FPs that you wish to display in a sub-panel, they must be created from a VIT and not a reentrant clone. I am using unnamed queues and passing the queue reference by value to all sub vis that need it because I have many spawned copies of the same code all using the same reentrant sub-vis and I need to make sure each spawned hiarchy uses it's own queue refs and not those from another spawned hiarchy. So each queue in the VI spawned from the VIT has only one create and one destroy. 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.