LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Question about re-usuing subVIS.

Solved!
Go to solution

Plain FGVs are not guaranteed against race conditions. You still need to use them in a proper way.

Benefits typically get bigger when you add functionalities (i.e. expand to Action Engines).

For example, if you have a global counter you want to increment, you need to read the global, increment and write back. If two parts of the code do this increment at the same time, it's possible that one of the increments is lost. But if you enclose the increment operation in an action Engine, the counter will be protected during the whole operation. This is a very trivial example of course.

Back to your original question: how to reuse a subvi with an internal storage? There are at least three ways:

- the simplest: duplicate the subvi as many times as you need it; this is not so bad as long as the vi code is stable,because you need to duplicate it again every time the code is changed

- a better way: set the vi as re-entrant and write a manager vi that will implement a pool of subvis; I attached an example using your own subvi; the good is that you don't need to duplicate vis when you change the code; the bad is that you need to access each instance by means of an index, plus the pool size is limited; however adding another instance is easy: just duplicate a case in the Case Structure

- a more flexible (but rather complicated) way: you still need a manager and an input index, however when the manager receives a new index, it needs to dynamically open and run an additional instance of the vi; the manager should maintain an array of the used indexes and an array of the vi references, furthermore you need a mechanism to close the references when they are not needed any more; this solution requires a good knowledge of how to open and call vis dynamically.

Paolo
-------------------
LV 7.1, 2011, 2017, 2019, 2021
Download All
Message 21 of 33
(909 Views)

@rajiv85 wrote:

My understanding is that we write an FGV to avoid a race-condition and to implement a non re-entrant writing. But it seems that a simple Sub Vi with a while loop and no enum (with read and write) is accomplishing the same result as an FGV. Am trying to understand the difference. Not clear to me.


Yes and no, a FGV - Functional Global Variable is a solution from LV2 to store and read data globally throughout a program, it has the same function as a Global variable but solves it through the 'trick' of using an uninitialized shift register to hold the data in a non reentrant VI. In many (most?) instances you'd be better off just using a Global variable. However, as a FGV is a standard VI used in a clever way it's expandable and modifiable in a way a Global isn't.

The only Race condition it can prevent is if you have some 'read and modify'-functionality that requires a seprate read and write function, in this case the non reentrancy will prevent any other process from accessing the data while it's updating. Well, if you add error in and out you can control _when_ data is handled to a larger degree than with a free Global variable, though you can force timing through e.g. a sequence structure, but that's a forum thread of its own. 🙂

 

So yes, any VI with an uninitialized shift register will function similar to an FGV, but an FGV is only meant to be a simple data storage. When you add more functionality than read/write it's called an Action Engine, and if you add even more it's called bad programming. 😄

 

What i gather from the others answers (i don't have LV on this computer), is that your Timeelapsed has a shift register, and then both will use the same stored data and influence with each other, this is expected with that design. This is the purpose of an FGV, you only want 1 set of data, in fact, if you want another one you need to copy the VI. If you want the VI to be reusable and independant, the solution is to send this data as inputs/outputs and use a feedback node in each instance. That way the VI have no internal data dependancy.

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
Message 22 of 33
(899 Views)

@rajiv85 wrote:

My understanding is that we write an FGV to avoid a race-condition and to implement a non re-entrant writing. But it seems that a simple Sub Vi with a while loop and no enum (with read and write) is accomplishing the same result as an FGV. Am trying to understand the difference. Not clear to me.


Go look at this: 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 23 of 33
(895 Views)

Adding to the post from @pincpanter.  A 4th way (when you're ready for it): define the FGV / AE behavior as member functions of a class.  Then each object you drop automatically carries a unique instance of the internal data & behavior.

 

Note: this is a moderately substantial departure in how you lay out your code, as each member function call will *require* you to connect input and output class wires which contain the unique (but hidden) data.  The objects travelling on the class wire hold the info that you *used to* hold in the uninitalized shift register.

    It can be a useful approach, but I wouldn't automatically advise going there immediately.

 

FYI: the specific terms FGV ("functional global variable") and AE ("Action Engine") are not formally and officially defined by NI as far as I know.  They are more like community tribal knowledge and jargon.  Over many years, the LabVIEW community, such as it is, has largely settled on a shared understanding of these terms. 

 

One other thing.  The "protection" aspect that pincpanter emphasized is a super-important aspect of what makes an AE valuable (and it would be retained by a switch to LVOOP and classes).  It allows actions to be *atomic* with respect to the data being changed, helping to prevent the race conditions that pure FGV's still allow, because app code does a "modify" between the FGV read and write.  In a properly-written AE, there's a "modify" action that remains atomic.

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
Message 24 of 33
(884 Views)

Very thankful for all the replies.

 

It definitely helped me tremendously to understand how they work. 

 

 

Message 25 of 33
(856 Views)

''If you want the VI to be reusable and independant, the solution is to send this data as inputs/outputs and use a feedback node in each instance. That way the VI have no internal data dependancy.'' Grateful if you could decript this 🙂 >>  ..''use a feedback node in each instance.''

 

So far my simple solution was to have them have 2 different names. Then later I figured out that I could configure them as clones, this means LV opens 2 independant instances of that SubVi.. 

 

In any case this seems to be a non trivial thing that could or should have been more explicitly explained in LV core 1 and 2 when making SubVis.

 

=> The unintended consequence of this thread is that I was able to understand that my simple subVI with a shift register is actually a FGV...( so a FGV is designed to have more functionalities than just read and write...) am wondering if for the plain purpose of writing and reading would that approach not be sufficient/ hence no need of writing a complicated action engine.. :S ?

0 Kudos
Message 26 of 33
(852 Views)

IF the timer VI is set preallocated clone reentrant it should maintain its state across multiple instances...

 

I wrote about Action Engines in this Nugget.

 

And just for the record, I have switched to feedback nodes and I have not written an AE that uses a shift-register in a very long time.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 27 of 33
(848 Views)

Thank you Ben.

 

Grateful if you could please post an example with the feedback node. Never seen one implemented for that purpose.

 

:Thumbs up:

0 Kudos
Message 28 of 33
(845 Views)

@rajiv85 wrote:

Thank you Ben.

 

Grateful if you could please post an example with the feedback node. Never seen one implemented for that purpose.

 

:Thumbs up:


That one is too easy and I will let someone else help out with that.

 

I wrote a blog about wrapping up AEs in Libraries that you can find here when you are ready for the next step.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 29 of 33
(831 Views)

@rajiv85 wrote:

Grateful if you could please post an example with the feedback node. Never seen one implemented for that purpose.


If you take the examples that I send through before as a starting point, its as simple as right clicking on a shift register and pressing "Replace with feedback node". See below.

 

http://zone.ni.com/reference/en-XX/help/371361R-01/lvhowto/replace_sr_with_feedback_n/

 

Jack

Message 30 of 33
(803 Views)