LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Timing of shared variables in dynamic referenced vi's

I am trying to troubleshoot someone's code where there are several shared variables in use and the primary function of the code is based on dynamically referenced vi's. Basically it is a test system with a full featured application that can call on any number of part number vi's to perform the actual test sequence for that particular part number.

 

I know the system was initially set up to use global variables but to try and eliminate those, he created shared variables. When an operator presses a start button, the specific test sequence begins as such: Reference to target part number vi is opened, referenced vi is executed, reference to vi is closed.

Because there is 2-way communication between the top level app and the referenced vi, (updating various results from the sequence, responding to prompts within the sequence, allowing an immediate stop test during the sequence, etc) there were initially globals and now shared variables used to facilitate this communication. With the shared variables however, there appears to be some timing issues as the variable in the referenced vi does not always appear to match the value as set in the top level vi.

 

My first feedback to the guy working it was to change the code so the reference only opens once while that particular part number is being tested as opposed to opening and closing it for each individual test sequence. This train of thought that perhaps the shared var's in the ref'd vi were having trouble syncing in time to be set properly while it executed.

 

Was looking at it yesterday and did find a couple race conditions but looks as if all those are resolved and still, when setting a shared var in the ref'd vi, it clearly does not update the shared var in the top level vi.

 

Any other thoughts on this?

 

Am going to consider having him change the shared var's out and instead use the Set Control Value by Index technique that I recently discovered an another thread. Since this relies on a single vi reference going into the individual referenced vi’s, this would be easy to feed in and would allow the same read / write functionality that is needed.

 

Any thoughts on this plan?

 

Eventually would like to look at LVOOP but that is a bit down the road.

 

Thanks for any feedback....

Doug

"My only wish is that I am capable of learning each and every day until my last breath."
0 Kudos
Message 1 of 11
(3,061 Views)

dacad wrote:

I know the system was initially set up to use global variables but to try and eliminate those, he created shared variables.


Sure, why not go to a system that has the exact same problems (race conditions) but it even slower.

 

Race conditions are way too abundant when it comes to global or shared variables.  A better solution would be to use Queues or User Events to pass data back and forth.


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
0 Kudos
Message 2 of 11
(3,057 Views)

So, shared var's are slower than globals. Hmmm. I agree on the liklihood of race conditions using [any] type of variable and I think that comes down to prudent and proper use of the variables and documenting your code well. I almost always use a variable as a "write few (or once) and read many" or "write many and read few (or one)"

 

Unless an event can drive an action in the referenced vi while it is executing, this only solves one direction of the communication, from the referenced vi to the top.

 

I could see queue's possibly being loaded up in the ref'd vi but timing could easily be an issue as the ref'd vi may need to pause while the top level loop executed. This would also force the addition of one or more loops in my top level vi which already has 5 loops going. Not the end of the world but not the most elegant solution from my perspective. This also will only be from the bottom up.

 

There are commands that require the ability to be sent to the ref'd vi regardless of where it is in it's execution. A key one being a stop test command. All the sub-vi's in the referenced sub-vi have a stop test function embedded in them or in there respective sub-vi's (so this is three and four and sometimes even 5 levels down) and commanding a stop test at the top level needs to feed all the way down regardless of where the ref'dvi is in it's execution. That value feeds back up stopping execution of each succesive vi on the way and finally stops the ref'd vi and exits is cleanly, resetting al the required things that need it.

 

Globals worked great and even though they are so frowned upon (other than the possibility for race conditions, why is that?) and in the end, that may be the cleanest if not most desired solution.

 

Am also looking to see if a functional global variable(s) could be a fit here. I find more uses for those all the time and actually do have one for a very flexible queue function that I have used quite successfully.

 

You don't like like the set control value by index option I am guessing? That actually seems a pretty simple method to me.

 

Would also still like to hear if anyone knows of timing issues when using shared var's in a ref'd vi.

 

 

 

Thanks......

Doug

"My only wish is that I am capable of learning each and every day until my last breath."
0 Kudos
Message 3 of 11
(3,047 Views)

Shared variables are completely asynchronous, if you are referring to network published shared variables. Because of this, it is possible to write to a value and then read back from that same value on the same computer and not see the value you just wrote to it.

 


Globals worked great and even though they are so frowned upon (other than the possibility for race conditions, why is that?) 


Race conditions should be enough 😛 They're also slower than wires, there is an extra data copy, and they're really difficult to follow. The other big reason is that they can't be used by reference, which means its harder to make reusable subVIs. Since the rule of thumb for globals is 0 or 1 writers and N readers, I prefer to use notifiers or user events instead. Can also use Data Value References but it sounds like the data you want to share is event-based anyway, I think crossrulz' answer is the right one.

 

0 Kudos
Message 4 of 11
(3,011 Views)

Yes, Network Shared Variables indeed did not work.  Another trial was completed using Single Process Shared Variables and it appears to work. Final testing has to be completed on the actual test system when it becomes available.  There is virtually no direct documentation however that I could find in LV concerning Single Process Shared Variables and it was just thru trials that it was discoverd to be a viable solution.

 

A trial was also completed using a Functional Global Variable (Action Engine) and it has also shown to work with the next level of testing required. It only has two modes, read and write and handles all of the items that I need to transfer back and forth between the top vi and the referenced vi.

 

In the end, if only one works on the system, that will be the choice, if both work then a review of efficiency (speed) and ease of deployment / maintenance will be completed to determine which will be used going forward.  My gut says the FGV will be faster as you are reading from / writing to terminals and local variables as opposed to the ShVar which runs slower than both of those though I am not sure if changing from a network to a single process will have an impact on that. The FGV also takes up less space in the block diagram the the ShVar and is a single entity as opposed to several ShVar's.

 

Without going into a novel, a brief explanation on events and queue's and why I do not believe they are the solution. Events are really not going to get the information to the referenced vi the way I need. When I change the value of a certain control on the main front panel, there are a lot of different subvi's several levels deep inside the referenced vi that need to be able to read the new value as they execute.  There is not always a specific place where that occurs and it will be different in the many different referenced vi's and their sub vi's that will be created going forward.

 

Queue's could maybe work but the deployment and maintenance will be more cumbersome as wires have to be maintained several levels deep.  Of course the queue could be developed into a Functional Global Variable (I have a nice one I use in some apps) but then, it the plain Funtional Global works, why make it more complicated by making it drive a queue.

 

If the overall app weren't so large, I would post it up but it's quite big and lots of stuff would break due to tasks, drivers, shared libraries and such.

 

My take on all this is that like most things, there are multiple solutions to everything. Some work better than others and some are easier to use than others. Is there a single heiarchy of methods that should be used to provide a single "correct" solution to be used?  I have to say no.  And like most things, everyone has theie favorite and preffered methods and sometimes can stay focused on these methods even if there may be an alternate solution that could make things better.

 

Certainly not throwing stones here, just making observations.  I get lots of good feedback on this forum and try to always look at the input objectively.

 

At some point in the future, I hope to learn enough about OOP to use that, as I think it could be the optimal method in this situation.

 

So thanks for the feedback even if I choose not to follow that path.

Doug

"My only wish is that I am capable of learning each and every day until my last breath."
0 Kudos
Message 5 of 11
(2,993 Views)

@dacad wrote:

A trial was also completed using a Functional Global Variable (Action Engine) and it has also shown to work with the next level of testing required. It only has two modes, read and write and handles all of the items that I need to transfer back and forth between the top vi and the referenced vi.


Again, you are better off with global variables.  Global Variables are actually faster than FGV (a read/write is NOT an Action Engine).  And FGV do not solve the actual issues of using global variables (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
0 Kudos
Message 6 of 11
(2,983 Views)

Another trial was completed using Single Process Shared Variables and it appears to work....A trial was also completed using a Functional Global Variable (Action Engine) and it has also shown to work with the next level of testing required.


 

 

Single process shared variables are just globals with error wires. As crossrulz mentioned, an FGV with a read/write method is worse than a global.

 


 

Without going into a novel, a brief explanation on events and queue's and why I do not believe they are the solution. Events are really not going to get the information to the referenced vi the way I need. When I change the value of a certain control on the main front panel, there are a lot of different subvi's several levels deep inside the referenced vi that need to be able to read the new value as they execute.  There is not always a specific place where that occurs and it will be different in the many different referenced vi's and their sub vi's that will be created going forward.


 

It sounds like you are saying you want to use globals because you don't want to wire the data around. Just based on the specific phrasing you used. This is a baaaad idea. If your options are "subVI with a parameter" vs "a global", you should really go for the parameter. The reason we suggested queues and events is not for data going to the subVI necessarily, but because you said you wanted to update the FP with data as you move through your tests. If your main UI isn't using events already, it should be, and if it is using events, its easy to add a custom event which your tests can throw in order to put data on the front panel.

 


 

My take on all this is that like most things, there are multiple solutions to everything. Some work better than others and some are easier to use than others. Is there a single heiarchy of methods that should be used to provide a single "correct" solution to be used?  I have to say no.  And like most things, everyone has theie favorite and preffered methods and sometimes can stay focused on these methods even if there may be an alternate solution that could make things better.


 

There are absolutely different ways to meet objectives, but when it comes to accomplishing specific tasks I tend to believe there are pretty fixed right and wrong ways to do something.

 

 

For a completely absurd example consider this: If you want to communicate between two machines there are many options: TCP, UDP, network streams, http, etc.... If you want to send an HTTP GET request to another machine and you start writing a queued message handler acting on a raw TCP socket instead of using the built-in function, you're likely doing it wrong.

 

So far in this thread you're asking questions of the second kind -- "what kind of global data should I use", basically. The answer is globals. Just globals. If you want to know how to transmit test parameters to subVIs or test results up to your UI, that is slightly higher-level and open to many different solutions. Your solution (globals) will work, but you should be aware of the problems you may face with them in the future.

0 Kudos
Message 7 of 11
(2,969 Views)

@crossrulz wrote:

dacad wrote:

I know the system was initially set up to use global variables but to try and eliminate those, he created shared variables.


Sure, why not go to a system that has the exact same problems (race conditions) but it even slower.

 

Race conditions are way too abundant when it comes to global or shared variables.  A better solution would be to use Queues or User Events to pass data back and forth.


Really, Globals, Shared Variables, FGVs and any other "Storage" mechanism have the exact same problem.  When you break dataflow you need to encapsulate critical sections of code.  Yet, I only here about the evils of storage here.  access to critical code sections (Those that should not be read to and written to while "other" things that may determine the values of those data happen) have been ignored.

 

What you have are not "Evil data storage"  You have unmanaged data access.  (Or my 8-Ball is off a bit this evening) 


"Should be" isn't "Is" -Jay
0 Kudos
Message 8 of 11
(2,966 Views)

Jeff·Þ·Bohrer wrote:

Really, Globals, Shared Variables, FGVs and any other "Storage" mechanism have the exact same problem.  When you break dataflow you need to encapsulate critical sections of code.  Yet, I only here about the evils of storage here.  access to critical code sections (Those that should not be read to and written to while "other" things that may determine the values of those data happen) have been ignored.

 

What you have are not "Evil data storage"  You have unmanaged data access.  (Or my 8-Ball is off a bit this evening) 


To which I say to read this very excellent blog post: http://labviewjournal.com/2011/08/race-conditions-and-functional-global-variables-in-labview/

It pretty much just confirms what Jeff is saying, but gives a lot more context in where we are coming from.


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 9 of 11
(2,945 Views)

Ok,  back from a nice long weekend and lots to digest here.   First, I totally agree that any type of storage container can be put into a race condition.  In the big scheme of things though these containers will always be used and in some to many of these cases, need to be used.  The variable here (no pun intended) is to decide which type of storage container to use and how to implement it to avoid the inherent pitfalls.

 

So I'm reading assorted feedback here that says yes and no to globals.  One of my original questions was, "What, other than race conditions, is the evil with global variables?"   If it is just race conditions then globals share this with pretty much any type of variable.  Nowhere have I read "Use a GV, it is the best type of variable to use",  rather it is always "Stay away from global variables" so that is why I am looking at all of the alternatives.

 


dems wrote:

 

Shared variables are completely asynchronous, if you are referring to network published shared variables. Because of this, it is possible to write to a value and then read back from that same value on the same computer and not see the value you just wrote to it.

 


     Globals worked great and even though they are so frowned upon (other than the possibility for race conditions, why is that?)


Race conditions should be enough :smileytongue: They're also slower than wires, there is an extra data copy, and they're really difficult to follow. The other big reason is that they can't be used by reference, which means its harder to make reusable subVIs. Since the rule of thumb for globals is 0 or 1 writers and N readers, I prefer to use notifiers or user events instead. Can also use Data Value References but it sounds like the data you want to share is event-based anyway, I think crossrulz' answer is the right one


 

So here I deduce both global variables and local variables make a copy of the data.  And you say that global variables can't be used by reference but I have running code (older) that shows otherwise.

 

Good info on the [network] shared variables. Being asynchronous seems like they would cause lots of problems.  Is this the intended behavior?  This might be in the LV help but I never ran across it.

 

 

Now, taking that a step further, some variables have features to make them less prone to race conditions, that being the inclusion of the error in/out wires. 

 

 


 

dems wrote:

 

Single process shared variables are just globals with error wires. As crossrulz mentioned, an FGV with a read/write method is worse than a global.

 


Did not know that about the single process shared variables.  Good to know. Could find pretty much nothing in the LV help to indicate the big differences between single process  and network shared variables.  Any good ref material out there?     You guys must have gobs of time to research all this, I sure don't which is why I post more questions that answers. Many more questions.

 

Now, in reference to the FGV being worse than a global as crossrulz indicated, other than a small speed hit, what else should deter me from using the FGV.  The plus for it is the inclusion of error wires and that I can include multiple storage containers in one package.  But then would the s/p shared variable be the best of both worlds?  The speed of the global with the data flow of the FGV.

 

What would happen if I put several s/p shared variable running parallel in a sub-vi?

 

 

I read the blog post referenced by crossrulz and it was informative though not groundbreaking.  Based on my interpretation, I still consider my FGV to be an action engine. There are only two cases, true, but there is also a wire to explicitly tell it which case to run.  I consider the critical section to be the updating of the values contained within the FGV.  I have attached it here though it is so simple that I could probably sketch it out as quick.

 

At the end of the day, there are several solutions I can deploy in this project, just looking to find the one that is simple to use, easy to maintain as additional product test sequences are added and is above the curve for not creating more problems than it solves.

 

Do appreciate the feedback, that which educates me, that which I agree with and even that which I don't agree with.

Doug

"My only wish is that I am capable of learning each and every day until my last breath."
0 Kudos
Message 10 of 11
(2,889 Views)