03-31-2017 09:44 AM
@Ben wrote:
One of the things I teach me peers is to spend some time thinking about the shape of an application.
What are the independent components?
When and where do the components interact?
What is the nature of the interactions?
And one of the most important question for a language based on the Data Flow Paradigm "where is the data and how does it move?"
It's more or less my job to help people figure out why their application isn't running as expected and these questions, particularly the last one, do a good job of highlighting the ways I have seen people misuse globals. If you can answer all of the above questions for your application, even when you are using global variables, we can probably work through problems without too many headaches (usually).
I see problems come up when using global variables when you can't answer the question "where is the data and how does it move?". Usually functions will do exactly what you tell them to do so you'll be debugging some code getting closer and closer to finding the error until you find your problem VI. You probe all of the inputs and find out that the function is doing exactly what you are telling it to do, you just don't know why it would use those inputs at that stage in the application. This is when you get some more coffee because, if the programmer before you misused globals, it can be extremely difficult to figure out where the data is coming from. It wasn't hard to figure out what was going wrong, but it can be a nightmare to figure out why it's happening, and by extension fixing the issue.
I don't think that this issue is unique to using global variables, but I do think it is much easier to abuse globals and get yourself into this situation. I caution against using globals too liberally because it can make fixing bugs or extending functionality difficult.
04-01-2017 04:01 PM
Nothing simpler than a Boolean global variable to interrupt a CPU intensive loop in a deep subVI (using a conditional terminal) from the UI.
Or is there?
04-02-2017 01:03 PM - edited 04-02-2017 01:05 PM
@Joannick wrote:
Why are Globals so evil if overused ?
The evil is in the "overuse", not the global. Overuse implies a use case that would work equally well, or even better with less. Overuse is always evil!
Of course you could get from point A to point B in a 1970'ies Buick, but at 6 mpg and no catalytic converter, the load on your wallet and on the air you breathe is arguably larger than with a reasonably modern car. I remember the stage 3 smog alerts from 30 years ago in Los Angeles and they were awful. They are now completely gone thanks to clean air regulations (see for example).
I almost never use globals because they require an additional file, complicating the hierarchy. An action engine is of course also consists of an additional file, but it can have added internal smarts, which I often need. (e.g. some global states need to change based on values of other global states) 😄
All that said, I am very proud to have a stacked sequence as a central element in one of my top programs. In this case, any other structure, even a flat sequence, would not fit that particular use case very well. There are always exceptions!
04-02-2017 08:09 PM
@altenbach wrote:
@Joannick wrote:
Why are Globals so evil if overused ?
The evil is in the "overuse", not the global. Overuse implies a use case that would work equally well, or even better with less. Overuse is always evil!
Of course you could get from point A to point B in a 1970'ies Buick, but at 6 mpg and no catalytic converter, the load on your wallet and on the air you breathe is arguably larger than with a reasonably modern car. I remember the stage 3 smog alerts from 30 years ago in Los Angeles and they were awful. They are now completely gone thanks to clean air regulations (see for example).
I almost never use globals because they require an additional file, complicating the hierarchy. An action engine is of course also consists of an additional file, but it can have added internal smarts, which I often need. (e.g. some global states need to change based on values of other global states) 😄
All that said, I am very proud to have a stacked sequence as a central element in one of my top programs. In this case, any other structure, even a flat sequence, would not fit that particular use case very well. There are always exceptions!
I need internal smarts! I wonder if a functional global would work for me?
04-02-2017 09:17 PM
@billko wrote:
I need internal smarts! I wonder if a functional global would work for me?
No, but an Action Engine will.
04-03-2017 08:14 AM
@crossrulz wrote:
No, but an Action Engine will.SpoilerFor those who don't know, there are some of us in the LabVIEW community who define a Functional Global as a Get/Set Action Engine. These are truly evil since they behave exactly the same as a Global Variable but with more overhead.
I haven't really thought about it in a long time, but I seem to recall that there is a slight but significant difference between functional globals and globals is that (non-reentrant)FuncGlobs have a bit of a mutex condition to them which protects against some types of race conditions. A read / write to a FuncGlob will not happen while another read / write to the FuncGlob is in progress due to normal vi locking, where as there is no such safety with a normal global, where a thread can overwrite the data while a read is occurring and vice-versa.
As I said, its been a long time since I considered the matter.
04-03-2017 09:04 AM
@Mythilt wrote:
@crossrulz wrote:
No, but an Action Engine will.SpoilerFor those who don't know, there are some of us in the LabVIEW community who define a Functional Global as a Get/Set Action Engine. These are truly evil since they behave exactly the same as a Global Variable but with more overhead.I haven't really thought about it in a long time, but I seem to recall that there is a slight but significant difference between functional globals and globals is that (non-reentrant)FuncGlobs have a bit of a mutex condition to them which protects against some types of race conditions. A read / write to a FuncGlob will not happen while another read / write to the FuncGlob is in progress due to normal vi locking, where as there is no such safety with a normal global, where a thread can overwrite the data while a read is occurring and vice-versa.
As I said, its been a long time since I considered the matter.
Jon,
A Functional global sharing a cluster and needing a single element of same to change would require a read to get the cluster, modify same outside the functional global and a write back to the global.
As long as the data (the cluster) is outside the FGV, the danger of race condition exists.
With AN Action Engine that has a method to "replace the cluster element INSIDE the AE" the mutex protect the encapsulated data.
Ben
04-03-2017 09:53 AM - edited 04-03-2017 09:57 AM
I decided to do a quick check on why I recalled what I did, and a quick websearch brought up the following article, which points out what I was originally recalling (The LabVIEW Core 1 documentation/course) and as my hazy memory indicated, it was supposed to be protection by the non-reentrant nature of the subVI call. (I never believed that FG's would block all race conditions, just ones caused by simultaneous access to the same dataspace in separate threads.)
Note also, my memory was faulty, since as you pointed out, just having the read/write wasn't enough.
http://labviewjournal.com/2011/08/race-conditions-and-functional-global-variables-in-labview/