More local variables.

I would like to organize code I have written into multiple vi’s but doing so would require me to make input and output local variables for each sub vi. I remember reading somewhere that you should avoid local and global variables because they will slow down your code. Is the slowdown at all significant or is there a better way to do this?

did you try clustering the variables and then making the cluster global? that may simplify things, especially if a lot of variables go between the same .vi’s.

How do the subVIs run? If one calls another calls another, like much of WPILib, then the typical approach is to pass the data in and out using a parameter. This is what happens if you select some code and use Edit>>Create SubVI from Selection.

If the VIs are going to loop forever, or for a long time, similar to how Periodic tasks or Vision does, then you need another communication mechanism. Globals are the one I’d start with. Be careful to write to a given global in only one loop and read it in the others, or you will start to see race conditions.

Greg McKaskle

Actually, I would warn against using Globals in LabVIEW. LabVIEW will actually avoid race conditions by automatically pausing the program to allow everything that needs to write to it to do so before anything can read. This can cause massive slowdowns, as well as otherwise inexplicable pauses in the code.

If you really need to communicate across VIs, make a VI whose only purpose is to serve and receive a value, as follows:

Indicator - Control

Perhaps I can clarify a bit. Data updates in LV are always atomic. They are protected so that competing writes will not corrupt the result, but they do not avoid race conditions – using the definition that NI teaches in its classes.

As an example, lets say that some loops are playing a game. Each loop is assigned a color from the rainbow, and they update a global with the color whenever they like. They don’t coordinate their updates, but since the writes are atomic, the color in the global will always be a legal color – “red”, “orange”, “yellow”, …, “violet”. You will never see odd combinations such as “blulet” or “violow”. To do this, LV must make the writes atomic using a lock or mutex. It adds some overhead to the value update, but it is certainly not a massive slowdown.

To show that, write the program to play the game on your laptop. Seven loops running full speed in parallel, each updating a variable with their color and the loop iteration they are on. I wrote mine to each update 1000 times. No race conditions or corruptions … yet.

Change the game so that the loops append their values, and you will start to see race conditions as shown in the second png. If you look carefully at the resulting data stream, you’ll notice that yellow skips number 309. Or rather, that the orange loop and yellow loop had a race. They both read the buffer, both updated, their local copy of the buffer, and then both wrote their string to the variable. In doing so, the yellow buffer that contained 309 was overwritten with the one from orange that was old. There is evidence of several other races in that portion of the buffer. You also get to see how the OS scheduler chooses to swap out threads. This laptop is a Core 2 Duo and you will see lots of interleaving, allowing more races.

To get rid of the race, you get rid of the read-modify-write access patterns that can interleave. In this case, the easiest way to do this is to build a subVI that accumulates the buffer. Each loop will pass in only the value to add “color #”, and since subVI are also atomic, no values are lost – ever. Again, this is a bit more overhead, but not massive. Making the subVI is a bit more complex than just a control wired to an indicator, but if you look in tutorials or examples, we refer to them as either “functional globals”, or sometimes as LV 2 style. The name refers to when this was this was the only way to get global data. LV used to be ever more functional and didn’t have global or local variables.

Back to the topic, it is really the access pattern that causes race conditions, and they aren’t necessarily bad. Just be aware when you are allowing them to happen. If you have only one writer to a global or other storage within your program there are no races.

Greg McKaskle

Screen shot 2011-03-26 at 7.33.25 AM.png




Screen shot 2011-03-26 at 7.33.25 AM.png

in my program i have locals being written and read from through out a sequence structure, but never the same local within the same frame. Would this ever cause race conditions?

Stupid question, but why not just pass the value(s) through with a wire?

If you only accessing the variable(s) from inside the sequence structure and never inside the same frame then you should not have a problem with race conditions.

My program records data to a file, then write that file to a local so that there is no slowdown or lag from reading. There are multiple cases and sequence structures depending on what button you press (probably about 7 or 8 different ones) so wires would make the code very messy and the whole point I’ve gone into this is to organize my 7 or 8 different options into separate VIs.