LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Modify only an element of a cluster in Function Global Variable (FGV) vi

Solved!
Go to solution

Hi,

 

I'm testing FGV but I'm a little confuse how I can modify only one element of a cluster. I first need to read the cluster, then change one element and then write the cluster.

 

If I understand properly, a race condition could happen between the read and the write. How can I prevent that?

 

This is just an example.

 

Thank you.

Download All
0 Kudos
Message 1 of 10
(4,395 Views)
Solution
Accepted by paubin

The race condition happens if something else tries to write to it at the same time.  Or if it reads from it at the same time it may get the new or the old data.

 

The solution is to build more cases into your FGV.  So have an Update Element "X" case.  Call that case with an input for that specific element.  That way the read shift register, replace element, update shift register all happens under the protection of the non-reentrant properties of the functional global variable.

Message 2 of 10
(4,378 Views)

The FGV is non-reenterant, so only the FGV effectively encapsulates the data in it's shift register. The only way a program can change the FGV data is going through one of the FGV cases (also called methods). Since the FGV can only operate one case at a time, it is not possible for another program to modify the data between the read and write you describe.

 

Race conditions are perfectly possible for programs that are using FGVs to communicate, like any variable. But this is best avoided by using FIFO variables, queues or user events.

CLA - Kudos is how we show our appreciation for comments that helped us!
0 Kudos
Message 3 of 10
(4,354 Views)

@MaxJoseph wrote:

The FGV is non-reenterant, so only the FGV effectively encapsulates the data in it's shift register. The only way a program can change the FGV data is going through one of the FGV cases (also called methods). Since the FGV can only operate one case at a time, it is not possible for another program to modify the data between the read and write you describe.

 

Race conditions are perfectly possible for programs that are using FGVs to communicate, like any variable. But this is best avoided by using FIFO variables, queues or user events.


Incorrect.  Yes the FGV is non-reentrant, but it only protects the data from changes while you are inside of it.  It can't protect the data when between the read and write calls of the same FGV.

 

1.  Piece of code A reads FGV cluster.  Lets say cluster as two elements A=1 B=1

2.  Piece of code A modifies element A of that cluster.  Now that wire has A=2 B=1.

3.  Piece of code B running in parallel reads FGV cluster.  It reads A=1 B=1  (because code A hasn't written back to FGV yet!)

4.  Piece of code A writes back to FGV.  Now FGV has A=2 B=1

5.  Piece of code B modifies element B on its wire.  Now that wire has A=1 B=2.

6.  Piece of code B writes back to FGV.  Now the cluster has A=1 B=2

 

RACE CONDITION.  Code A's data modification is now lost.  The use of FGV's don't prevent race conditions, at least not when they aren't used properly.  The non-entrant setting only prevents the code when it is inside the FGV.  To use the FGV to protect the data, you need to move the modification inside the FGV.  You can have two separate "Write" cases, "Modify element A" and "Modify Element B"

 

Message 4 of 10
(4,337 Views)

I understand. I will focus only on critical elements then and I will add cases for those.

 

I think that this will help me clean my program because I was keeping all critical global variables outside of a cluster because I had race conditions when using them inside a cluster.

 

I will try. Thank you.

 

0 Kudos
Message 5 of 10
(4,331 Views)

@RavensFan wrote:

Incorrect.  Yes the FGV is non-reentrant, but it only protects the data from changes while you are inside of it.  It can't protect the data when between the read and write calls of the same FGV.


I go through a bunch of variable methods in this document: A Look At Race Conditions


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
(4,318 Views)

The term I use is mentioned in my Nugget about Action Engines that you can find here.

 

The distinction that I draw between FGV and Action Engines (AE) is  AE's include methods that act on the encapsulated data.

 

But since you are exploring AEs and since that thread is rather long I have tow suggestions that really help with reading the code, supporting it and managing data that we need to share between threads.

 

1) For every Action create a wrapper that exposes inputs (preferably required) and invokes the AE.

For AEs that have a lot of methods (actions) and are used in many places, finding where an AE is being invoked with a specific method could require looking at a bunch of instances and inspecting when method is being invoked. If each method has a wrapper you can search for the wrapper to zero in on the method you are investigating. The wrapper will reduce any confusion that other may have in using your AE since YOU know what each methods needs and could also include validity tests of inputs if you want to go the extra mile.

 

2) Create a Library for you AE and the wrappers.

Libraries are useful in that you can put the AE in a private folder and prevent others from calling the AE "naked". It forces them to use a wrapper (in a public folder) to invoke the AE methods. The library gives you the option to use a common template for the AE and the associated wrappers. It also gives you the option to "group by Libraries" when looking at the Hierarchy screen AND you can collapse libraries to clear the hierarchy so you can focus on the general call structure. The other feature of using libraries with AEs is in the event you need another AE to do something similar but different, then you can easily do a Save As" on a library to get a clone of the original library with all cross-linking avoided. I wrote about many of these advantages in this blog article where I illustrated these features.

 

Bottom line with AEs...

 

The data is in the AE!

 

Everything else is either a sample or a copy of what is IN THE AE.

 

Ben 

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 7 of 10
(4,315 Views)

Hi again,

I would appreciate to have suggestions about my architecture.

I firstly did a prototype using all global variables all over my coding. (inside VI, subVIs,etc).

 

Yes, that's not correct because now I want to reuse all those VIs but for an other unit that is controlled by the same controller. My goal is to be able to maintain one version of the same VIs. That's is why I began testing "array of cluster" where all my writable data reside in that cluster. I then experimented race conditions in my code and finally ended up reading and trying FGV wit AE.

 

I have four (4) timed loop of the same VI but with different data, so I build an FGV that is an array of clusters, each cluster of the array represent one unit. My questions is should I regroup all data in the same cluster for 1 unit and then build array or it's not a good thing to do? I feel that I rewriting the whole cluster just to change one (1) element and that each timedloop wait (a little bit) to write in the FGV. 

 

I also feel like I have to make a case (AE) for all element I have to write. Is it normal?

 

Thank you,

Patrick

 

 

0 Kudos
Message 8 of 10
(4,208 Views)

@paubin wrote:

 

 

I have four (4) timed loop of the same VI but with different data, so I build an FGV that is an array of clusters, each cluster of the array represent one unit. My questions is should I regroup all data in the same cluster for 1 unit and then build array or it's not a good thing to do? I feel that I rewriting the whole cluster just to change one (1) element and that each timedloop wait (a little bit) to write in the FGV. 

Yes.  I would consider regrouping your data structures.  So that there is a cluster for one unit, and array that contains all units.

 

I also feel like I have to make a case (AE) for all element I have to write. Is it normal?

Yes.  When you want to change each element individually, you're going to need a case for each.  How else would the action engine know which element you are trying to change?

 


Be sure to use type def's for the enum that determines which case of the action engine you want to run, as well as one for the cluster that contains all the elements.  If you don't, you'll quickly run into problems if you ever had an element to the cluster later, or a need item to the enum as you'd have to update those clusters and enums in numerous places.  Using typedef's would allow those updates to occur automatically.

0 Kudos
Message 9 of 10
(4,201 Views)

 

I'm currently using typedef.

I will try to avoid reading back and forth for nothing and just write once per loop iteration.

 

Thanks for your suggestion.

0 Kudos
Message 10 of 10
(4,197 Views)