LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Locking access to Global Variables to avoid race conditions??

Solved!
Go to solution

Hi All,

 

I am developing an application where a 'control' subVI is accessing an 'action' subVI. The action subVI is actually accessed by a number of different high-level subVIs to I definately need to use globals.

 

I wrote the following piece of code and was struck that it might lead to a race condition. Essentially my control subVI runs two loops in parallel. Each loop reads the global, increments a different value in each one, waits a set amount of time and then returns the value to its previous value.

 

I've written this piece of code to demo what I'm talking about. The  Waveform chart takes the place of the 'action' subVI. Running this code has resulted in a race condition (one of the values goes from 0-5 range to 5-10 range) after being loaded into memory running a second time usually lets it run for a long time.

 

race_conditions.PNG

I modified the VI to exaggerate the effect of the race-condition for demonstration. I also implemented a solution by using a local variable to stop the globals being accessed at the same time. However it is far from elegent and I don't think it will work for more than two loops. I eventually need to use three loops.

 

 

I've attached my exaggerated demo/solution. If you can suggest a better way to solve this problem I'd be much obliged.

 

Thanks,


Dave

 

 

0 Kudos
Message 1 of 11
(7,480 Views)

DeltaJ wrote:

 

I am developing an application where a 'control' subVI is accessing an 'action' subVI. The action subVI is actually accessed by a number of different high-level subVIs to I definately need to use globals.


Actually, you don't - you can use queues.

 

I would strongly suggest reading the Action Engine nugget

Message 2 of 11
(7,478 Views)

I just walked out of the lab for some fresh air - after staring at this problem for hours - and it hit me. If I write access to my Globals within a subVI - which I can do - and make the VI reentrant won't the program only be able to access the globals in sequence and avoid the race-condtion that way?

 

Thanks,

Dave

 

 

0 Kudos
Message 3 of 11
(7,477 Views)

I actually can't use queues for this application (or atleast not without a major re-write). I'm afraid I'm stuck with the globals! Its due to the timing of my 'arbitrary interval' - if the actions are queued rather than happen in parallel one might occur too late. I can have my timing out by 100-200ms without effecting my process but any more than that and and my process fails! And the actions themselves take about 3 seconds so queueing will really throw my timing out!

 

Or do you mean I can queue access to the global - I may be able to do that without a huge re-write!

 

And I'll certainly read that nugget - thanks for the suggestion.

 

Dave

 

 

 

 

0 Kudos
Message 4 of 11
(7,471 Views)
Solution
Accepted by topic author DeltaJ

DeltaJ wrote:

I just walked out of the lab for some fresh air - after staring at this problem for hours - and it hit me. If I write access to my Globals within a subVI - which I can do - and make the VI reentrant won't the program only be able to access the globals in sequence and avoid the race-condtion that way?


A reentrant VI uses its own separate memory space for each instance so it means it can be called in parallel with another instance. This means it just gives you the same situation as what you currently have. 

 


Or do you mean I can queue access to the global - I may be able to do that without a huge re-write!

No, I wasn't talking about queueing access to the global. I was talking about storing the data in a queue.

 

Encapsulating the updating of the value in a subVI is what you would do with an Action Engine. Note that you want an "update" action so the read/write occurs inside the Action Engine VI.  This will give you as close to an atomic operation that you can get. 

 

Message 5 of 11
(7,450 Views)

I've tried it by putting my read/write actions in a subVI (non-reentrant - my mistake about that) and it is working perfectly. And I'll definately try to use action engines in the future. Thanks for all your help.

 

Dave

 

 

0 Kudos
Message 6 of 11
(7,428 Views)

Hi DeltaJ,

 

Many thanks for contacting National Instruments with your query regarding how to avoid Race conditions. I just wanted to point out a couple of additional ideas that you could try as well as using non-reentrant subVIs. 

 

1. Semaphores

You can use Semaphores to basically lock a resource. They don't have any queueing capability but they do allow you to control access to a shared resource.  There are a few resources that I've linked to this post so that you can investigate these further in your own time. This article details some information on how to implement semaphores and this article details an exercise that you can work through to learn how they work.

 

2. Functional Global Variables

These are essentially the same as the  Action Engine Vis that have already been mentioned. Here is an article that explains them a little further.

 

If you are looking for more information about this sort of application, I really recommend going on the LabVIEW Basics II course. This course deals in quite some depth about global variables, shared variables, local variables and race conditions. It also covers some of the more advanced design patterns such as master/slave and producer consumer.

 

I have attached a sample of the Basics II course and what it covers. 

 

Please let me know how you get on.

 

Many Thanks,

Andrew McLennan
Applications Engineer
National Instruments
Message 7 of 11
(7,414 Views)

Hi Andrew,

 

Thanks for the additional information,

 

Regards,

 

Dave

 

0 Kudos
Message 8 of 11
(7,399 Views)

DeltaJ wrote:

I've tried it by putting my read/write actions in a subVI (non-reentrant - my mistake about that) and it is working perfectly. And I'll definately try to use action engines in the future. Thanks for all your help.

 

Dave

 

 


 

Hi Dave,

 

You are walking the same path I did about 10 years ago. Although your warpper will control access to the global there are two other issues that I would like to point out to motivate yout o loose the globals.

 

1) Each instance of the global will require a data copy. if you switch over to the SR version, you can minimize your meemory req's and improve the performance since you will not have make the extra copies of the data.

 

2) Some day after you have moved on to bigger and better things, there may be some young noob asked to enhance your code. They may make the make the mistake of accessing the global outside of your wrapper and the next thing you know your ears are burning.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 9 of 11
(7,397 Views)
Another option: use OO. With a class you have accessor functions to update values of each member. Similar in concept to the Action Engine, but wrapped up in a nice comfy OO blanket.
Message 10 of 11
(7,390 Views)