03-24-2015 06:49 AM
This is such a simple question but I can't find an answer to it. The accepted pattern for a Functional Global Variable is to use an uninitialized shift register like this example:
("Reference IN" and "Reference out" are actually a cluster of references.) There is also a case for "Get Refnum", which just tunnels the shift register straight through.
My question is, why can't I store the data in the Indicator? This is much simpler than using a shift register (IMHO a non-obvious way to store global data!):
The "Get Refnum" case does absolutely nothing. Other functions like clearing the data can be implemented just as easily. The FGV advantage of helping to avoid race conditions is maintained because you are still running the VI to access the data.
Solved! Go to Solution.
03-24-2015 07:02 AM
03-24-2015 07:04 AM
Does it strictly work in the case of a purely FGV (not Action Engine) and if you are careful? Yes.
However, it is NOT the correct design. Although you have stated that in your opinion a shift register is a non-obvious way to store data, consider the following:
Also, you should put your controls (including the action control "Store/Get Refum" and the input "Reference IN") outside of the FGV's while loop.
03-24-2015 07:07 AM
@mikeporter wrote:
This doesn't work because there is nothing to store the data. If you are looking for an alternative FGV implementation, checkout the feedback node.
Mike...
The data would be stored in the indicator's value. If you don't write to the indicator in the Get state (JonP stated that the state is empty), then a caller would get the previous value on the indicator's terminal.
03-24-2015 07:15 AM
I merely said that the shift register is a non-obvious way to store global data, it suits me fine for data that needs to be preserved between iterations of a loop.
It may not be the "correct" design, I just wanted to know why not. Of couse if you are using the FGV to store an array of data and only asking to read one item at a time there will not be an indicator for all the data, so the shift register is your only option.
And it works! This may be by chance, but I believe NI state somewhere that the values of Controls and Indicators are preserved between calls, I'll try to track this quotation down...
Jon
03-24-2015 07:24 AM
@JonP wrote:
I merely said that the shift register is a non-obvious way to store global data, it suits me fine for data that needs to be preserved between iterations of a loop.
It may not be the "correct" design, I just wanted to know why not. Of couse if you are using the FGV to store an array of data and only asking to read one item at a time there will not be an indicator for all the data, so the shift register is your only option.
1. And an Indicator is an obvious way to store global data?
2. You are not using a shift register to store global data. You are using a functional global variable to store global data. Internal to that FGV, a shift register is used to store the local data that enables that FGV to do its job.
3. It's not just storing an array and requesting single values. It is anything other than Get/Set. For example, say that you want to support Get, Set, and Clear (rather than Set with an empty input). Both Clear and Set would have to write to the indicator in your design. However, the indicator has to live INSIDE of the case structure in order to get your design to work, so both cases will not be able to access it. You would have to either use a Local Variable (the WRONG decision, for performance and scalability), or take the indicator out of the case structure and put a while loop with a shift register around the case in order to hold the value ... oh wait a minute, that's the classic FGV design
This may be by chance, but I believe NI state somewhere that the values of Controls and Indicators are preserved between calls, I'll try to track this quotation down...
Values of Controls and Indicators are preserved between calls, which is why it strictly does work.
03-24-2015 07:41 AM
> 1. And an Indicator is an obvious way to store global data?
Just as obvious as an uninitialized shift register, especially if LabVIEW defines that indicator states are preserved between calls. This is only a personal opinion of course, but I have rad other posts that say the shift register mecahism is a bit of a kludge or some words like that.
3. It's not just storing an array and requesting single values. It is anything other than Get/Set. For example, say that you want to support Get, Set, and Clear (rather than Set with an empty input). Both Clear and Set would have to write to the indicator in your design. However, the indicator has to live INSIDE of the case structure in order to get your design to work, so both cases will not be able to access it.
Not so, the Inidicator can happily live outside the case structure, Set and Clear would just assign different values to it. The difficulty comes with fetching the value if you want to do a read-modify-write operation. But LV provides plenty of ways to fetch the data from an indicator (one you don't mention is the "Value" property node), are you saying these are all "incorrect"? I suppose you might say that Indicators should only be written but it's tough to be that pure!
Anyway, thanks for your reply, I appreciate your views which I think boil down to "you should use a shift register because it satisifes LabVIEW's style guidelines", right?
03-24-2015 08:10 AM
@JonP wrote:
Not so, the Inidicator can happily live outside the case structure, Set and Clear would just assign different values to it.
If you only have one case structure, then the Indicator could not live outside of it. In order to maintain the data in the Indicator, your design requires that it is not written to for a Get case. You could have an outer case structure that decides on "Get" or "Set or Clear" and (in the "Set or Clear" case) contains the Indicator terminal and a case sctructure that decides on "Set" or "Clear". However, I would consider this an inferior design to using the standard FGV design.
The difficulty comes with fetching the value if you want to do a read-modify-write operation. But LV provides plenty of ways to fetch the data from an indicator (one you don't mention is the "Value" property node), are you saying these are all "incorrect"?
Yes (I am saying these are all incorrect).
You could hack your way around getting the design to work with a single case structure and the Indicator's terminal being outside of it by using a method to read the Indicator's value and pass that through a tunnel to the case structure, wiring it through to the Indicator write tunnel in the "Get" case. However, that is going to require either a Local Variable or Value Property Node. As I said, these (I only mentioned Local Variable originally) are not good choices for performance and scalability. If you are not aware of the functional differences between Terminals, Local Variables, and Value Property Nodes, reference this KB article (obviously pros/cons such as re-drawing front panel objects are not relevant in this case).
I suppose you might say that Indicators should only be written but it's tough to be that pure!
No it's not, you just use the classic FGV design!
03-24-2015 08:40 AM
OK, points taken, although I was referring to the general case, not just to FGVs, when I said it is tough to be pure.
My personal conclusion: A guiding principle in my lengthy software experience (not so lengthy with LV as you can probably tell!) is to keep the code as simple as possible. In the case of a simple Get/Set FGV (no need to read the indicator) I think using the indicator is the simplest solution but I agree that for anything else the single-iteration loop (how can that not be a kludge) with a shift register or, a bit better, use of a feedback node is probably best.
Jon
03-24-2015 10:03 AM
You can write the FGV with a feedback node instead, if you feel that makes it purer, but the compiled code should be the same.
/Y