LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

LV2 style globals with call-by-reference VIs

    Hi all experts,

I am trying to implement data sharing between two VIs, and am having undesired behaviour. To elaborate:

I have a main GUI, which opens another VI using call by reference. I would like to use a LV2 global to share (read and write) data between both VIs, however it sometimes seems to not work properly (in the second VI the data in the LV2 global is not the same as the data that is set in the main VI). Is it possible to use a LV2 global in this manner? I did a search on the forum and got some info about using references to the LV2, but I have not implemented this before, so am not entirely sure if this will work.

Regarding references, this is as I understand it:  instead of putting the LV2 VI in both the block diagrams, I would encapsulate this LV2 in another VI which would have an input that is a reference to the LV2? Now I am confused! Smiley Sad

I would be most grateful if anyone could shed some light on this?

Thanks in advance
Neil
0 Kudos
Message 1 of 16
(5,114 Views)

Hi Neil,

I have used variations on that concept going back to BridgeVIEW 2.1.

Please post your test VI and let us take a look.

I have not tried this with LV 8.X yet and I seem to remeber there may have been some changes that affected this, but I am not sure about thta point.

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 2 of 16
(5,102 Views)
Hi Ben,

Thanks for your quick reply. I have quickly made a simpler program, which I attach, which seems to function correctly! I am a little concerned about the potential race-condition of using a set LV2 function in the second VI. My real app is significantly more complicated, I was hoping this little test would actually fail, however as it has not I have to assume I am doing something else silly elsewhere!

I would be very interested in your comments, as this (my real app, not this attached one!) is essentially my first program where I have attempted to use LV2 style globals throughout. I dont really want to go down the wrong style/path completely.

The reason I wanted to use a call-by-reference is I need to do some DAQ whilst a state machine in my main VI is doing something. I thought by essentially spawning off the DAQ into its own pseudo-thread I would not have to change the structure of my main state machine.

Thanks again
Neil

0 Kudos
Message 3 of 16
(5,098 Views)

sigh, why do my attachments never work??? I try repost using Internet Explorer instead of Firefox.

ps: I am using LV7.1

0 Kudos
Message 4 of 16
(5,091 Views)


@nrp wrote:
I have a main GUI, which opens another VI using call by reference. I would like to use a LV2 global to share (read and write) data between both VIs, however it sometimes seems to not work properly (in the second VI the data in the LV2 global is not the same as the data that is set in the main VI). Is it possible to use a LV2 global in this manner?

Could it be that your LV2Global is accidentally set to reentrant execution?

Are you absolutely sure you are using the same LV2 global VI in both locations?

Message 5 of 16
(5,090 Views)
I am pretty certain its the same LV2 global in all locations, as it works under certain conditions, albeit sporadically! It is not re-entrant.

Do you recommend for/against this type of design pattern?

0 Kudos
Message 6 of 16
(5,083 Views)


@nrp wrote:
Do you recommend for/against this type of design pattern?

LV2 style globals are great and highly recommended. 😄
 
I would guess you're having race conditions due to the fact that possibly multiple locations write to it at arbitrary times. Also, Is it a possible that you forgot to wire one of the shift registers across on one of the cases of the LV2G subVI?
Message 7 of 16
(5,078 Views)
my guess would be race conditions also, as I do have multiple read/write possibilities (and the LV2 is quite simple, just set/get/clear methods). This is a can of worms though, I suppose I need some kind of semaphore or locking mechanism? Any ideas on a simple, but effictive semaphore method?

otherwise, I can try and simpify my main app to find out if it is a race condition, and if so where it is all going wrong. I have not discounted the possibility of a silly unwired input though, I will have to go back and check everything!



0 Kudos
Message 8 of 16
(5,046 Views)
altenbach,

I think I know whats going wrong with my program. Regarding LV2 style globals, do I need separate accessor methods for each variable that I wish to change? Currently I only have a single set and get function which operates on a large cluster of variables. So every time I wish to set a variable I have to use the Get function (to retrieve the previous contents of the LV2) and then pass that cluster into a bundle-by-name which has the new value of the (usually) single element of the cluster I wish to change. This seems to work fine in simple apps, but when I have multiple get-set operations it is possible that a normal get-set sequence can be interrupted by another get-set sequence somewhere else in the code? ie. if I have getA, "do something", setA (where getA means get from LV2 global in position A in the code) then its possible that if "do-something" take too long it can be interrupted by getB-setB, so the sequence would be getA-"do something"-getB-setB-setA, and the LV2 setA operation would NOT retain the value just set in the setB as it would use its previously read value from the getA operation.

do I have my logic correct here?

ps: apologies if this makes no sense at all!


0 Kudos
Message 9 of 16
(5,037 Views)

Hi Neil,

Please see the examples I posted in reply #13 & 14 of this thread.

http://forums.ni.com/ni/board/message?board.id=170&message.id=204323#M204323

Those VI's comprise a very simple example of the "Action Engine" i.e. LV2 with brains.

Any time I have a data structure that must be manipulated from more than one place, I will concider using an Action Engine.

It greatly simplifies the management of shared data structures in what I feel is a very elegant manor.

The Action and LV2 have to be set as  NOT re-entrant to work. If they are re-entrant, they can be executed at the same time by more than one caller, and this is made possible by giving each instance a distinct data space. The district data space makes it impossible (?) to share the data across instances.

Now if the VI is NOT re-entrant, they have a single data space for every instance of the VI. This means if I leave some data behind from one, a latter call can get at that data. Now to prevent the wires of a shared non-re-entrant VI form having to hold the values from more than one call, only one of the calls is allowed to execute at anyone time. This is the key to what makes these action engines powerful. LV in the background miantians a set of mutexes to prevent more than one call to take place at any one time. It is this "locking" that helps us prevent race conditions when using action engines.

Enough background ideas!

When designing your action engines, make sure that any manipulation of your data structure takes place inside the action engine. AS long as it is inside the action engine, other attempts to manipulate the data are forced to wait until the previous is complete.

Food for thought:

If you have data structures that are dependant on other data structures, then you can  call one action engine from within another action engine.

Done rambling.

I hope some of this helps.

Ben

 

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