12-07-2012 01:17 PM - edited 12-07-2012 01:17 PM
12-07-2012 01:47 PM - edited 12-07-2012 01:49 PM
Funtional Global Variables implement Mutual Exclusion to their contained code i.e. the section of code contained within the FGV can only be executed once at a time by all the competing concurrent accessing processes. With this in mind, all of the code inside will be executed whilst a single task has access to it and then released once the FGV has finished operation. The contained structures such as your Loops and Case Structures are not in themselves shared resources, so there's no problem with race conditions in that regard.
You'd only have to worry if the Functional Global Variable was writing to other shared resources in a way that isn't properly synchronized.
12-07-2012 06:47 PM
Here's a good article on FGVs and race conditions from the LabVIEW Field Journal:http://labviewjournal.com/2011/08/race-conditions-and-functional-global-variables-in-labview/
04-23-2013 12:58 AM
I'm being a bit dense here... would somebody write an example VI that demonstrates how functional global variables eliminate race conditions whereas a normal global variable would not? Or just describe it and I'll write the VI?
04-23-2013 01:08 AM
@bmihura wrote:
I'm being a bit dense here... would somebody write an example VI that demonstrates how functional global variables eliminate race conditions whereas a normal global variable would not? Or just describe it and I'll write the VI?
I believe there are threads on this, so try a search and see if you can find some. I do want to clear something up. Functional globals are not an overall solution to race conditions. When used correctly, they can be. When used incorrectly, they can be just like a global variable. The key is to do all your processing which uses the data stored in the FG within the FG. If you don't, and you leave the functional global and then call it again, there is the possibilty that the data was updated somewhere else. This gets into the Action Engine relm. Read that thread and see if it helps clear things up.
04-23-2013 08:13 AM
@bmihura wrote:
I'm being a bit dense here... would somebody write an example VI that demonstrates how functional global variables eliminate race conditions whereas a normal global variable would not? Or just describe it and I'll write the VI?
The classic example used is a bank account. Say you are making a deposit. You have to read the current balance, add the deposit amount, and save the balance. Now say you are making a withdrawal. You have to read the current balance, subtract the withdrawal amount, and save the new balance. Now let us say that both of these events happen at the same time.
If you are using global variables, you read the global, perform the action, and save to the global. But who reads what balance. If both events read the balance at the same time, then whoever writes last will overwrite the other's action. This is bad, especially if your deposit "didn't happen".
Now using a FGV (or Action Engine), you can contain the critial parts of the code. In this case the critical parts are the full read, act, and write. So with the AE, you store the balance in a shift register. You can perform whatever action you want inside of the AE VI. Because the AE is not reentrant, only 1 action can be performed at a time. So you make sure that deposit happens and is not overwritten by the withdrawal.
Now for my caveat. If all you do is a Get and Set inside of the FGV, it is basically a global variable, just slower.
Read that acticle I linked to earlier and also read up on the Action Engine nugget.
04-23-2013 11:14 AM
Thanks for that Action Engine link, it contained the key piece of information that has hopefully cleared me up:
VIs that are not reentrant can only be executing in one context at a time. LabVIEW will ensure that if there is ever a situation were two contexts are attempting to act on the same AE at the same time, LabVIEW will schedule the first and the subsequent will wait until the first call completes.
So if we have a non-reentrant subVI running in two parallel loops, and it has a "critical section" of code like a read-modify-write to some shared memory, it will be safe as if it had a semaphore wrapping that critical section?
04-23-2013 12:16 PM
@bmihura wrote:
Thanks for that Action Engine link, it contained the key piece of information that has hopefully cleared me up:
VIs that are not reentrant can only be executing in one context at a time. LabVIEW will ensure that if there is ever a situation were two contexts are attempting to act on the same AE at the same time, LabVIEW will schedule the first and the subsequent will wait until the first call completes.
So if we have a non-reentrant subVI running in two parallel loops, and it has a "critical section" of code like a read-modify-write to some shared memory, it will be safe as if it had a semaphore wrapping that critical section?
Correct, as long as you do all these in the action engine without the subVI completing until all actions are done.
04-23-2013 12:18 PM
In my mind a semaphore is implied with each non reentrant Vi in memory since this VI is singleton in memory and LV will schedule access to it
based on execution (data) flow.
Now what happens when two of these VIs are executing on the block diagram together in parallel and there is no data dependency?
That's where the race condition comes from in my mind since the withdrawel may happen first before the deposit.
04-23-2013 01:23 PM
@AKA_TG wrote:
In my mind a semaphore is implied with each non reentrant Vi in memory since this VI is singleton in memory and LV will schedule access to it
based on execution (data) flow.
Now what happens when two of these VIs are executing on the block diagram together in parallel and there is no data dependency?
That's where the race condition comes from in my mind since the withdrawel may happen first before the deposit.
Yes, non reentrant VIs are a lot like using semaphores. Things made a lot more sense to me when I made this realization.
There will always be a race about which action will happen first. That is just life. But when you protect the critical code, the data itself is not subject to a race condition.