LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Is a functional global with loops inside case structure subject to race condition?

Solved!
Go to solution

Such as this one:

 

Picture2.jpg

0 Kudos
Message 1 of 10
(2,602 Views)
Solution
Accepted by topic author Bo2008

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.


Alex Thomas, University of Manchester School of EEE LabVIEW Ambassador (CLAD)

0 Kudos
Message 2 of 10
(2,587 Views)

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/


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 3 of 10
(2,557 Views)

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?

0 Kudos
Message 4 of 10
(2,454 Views)

@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.

Message 5 of 10
(2,450 Views)

@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.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 6 of 10
(2,438 Views)

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?

0 Kudos
Message 7 of 10
(2,415 Views)

@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.

Message 8 of 10
(2,404 Views)

 

 

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.

 

 

 

 

 

 

Message 9 of 10
(2,403 Views)

@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.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 10 of 10
(2,385 Views)