From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Using same sub vi code in different data spaces of a project

Solved!
Go to solution

@pushkin wrote:

"Assuming that you’re only calling the ci once for each datatype then you already have your solution."

 

I am not making this assumption.  I want to call the vi multiple times for the different Persistent data sets from different locations.

I generally have multiple activities/executions (with a ctl as a parameter) for the  different Persistent data sets.

 

Regards JC.......


OK, it's still entirely unclear about what you are wanting to do. Are you saying that within a given data set you do not have a central location where you can call this vi? If that's the case then perhaps you need to rethink your structure. What I keep hearing you say is that you want the data to persist for each individual data set. I don't understand the "with a ctl as a parameter". What do you mean by that? Can you share some example code showing what you're really trying to do? 

0 Kudos
Message 11 of 23
(790 Views)

The discussed assumption was that I am calling it once for a particular Persistent data set.

This is not the case.

I will stay away from my further elaborations on style.

Thank you.

Regards JC....

0 Kudos
Message 12 of 23
(784 Views)

@pushkin wrote:

The discussed assumption was that I am calling it once for a particular Persistent data set.

This is not the case.

I will stay away from my further elaborations on style.

Thank you.

Regards JC....


OK, now you're talking plainly. Your previous wording was very vague. I would personally still try to avoid making multiple copies of the same vi - this becomes extremely tedious for larger projects. 

 

While this isn't the way that I would do it, perhaps with your current code base it would work. You could use single element named queues to store the persistent data and have a specific name for each data set. This would allow you to call the specific persistent data set anywhere that you wanted in the code. 

 

Another option would be to create an array of data. There would be two arrays in your persistent data - the first would be an identifier for the persistent data instance and the second would be the corresponding persistent data. Your vi would take the identifier and work on the appropriate data. You could even make this grow as you add persistent data instances.

 

Either of these methods require a little bit of work but only one vi that can readily be used no matter how many instances of persistent data that you need.

 

I would probably still look at creating classes and storing the data in the class, but that's my personal preference.

Message 13 of 23
(782 Views)

"You could use single element named queues to store the persistent data".

 

I need an example?. 

 

I am discussing vi programs and how that relates to the Temporary data (i.e. initialised on each execution) and the possible different Persistent data sets.  This is the program and how it connects to the various possible data spaces.

 

Regards JC.....

0 Kudos
Message 14 of 23
(773 Views)

@pushkin wrote:

"You could use single element named queues to store the persistent data".

 

I need an example?. 

 

I am discussing vi programs and how that relates to the Temporary data (i.e. initialised on each execution) and the possible different Persistent data sets.  This is the program and how it connects to the various possible data spaces.

 

Regards JC.....


Your post is totally confusing. Your initial post indicated that you had a subvi for which you wanted data to persist through multiple calls within a given data space. From where does this "persistent data" originate? How is this data being stored in your subvi (uninitialized shift registers is the normal way)? 

 

@pushkin wrote:

 

I generally have multiple activities/executions (with a ctl as a parameter) for the  different Persistent data sets.

Does this mean that you're using default values of controls within your subvi as your "persistent" data set? If so why not use global variables and have the subvi read the correct values based on the context (could use a string or enum as an input to give it the context).

0 Kudos
Message 15 of 23
(757 Views)

We could avoid all this discussion if we had a simple example that shows the idea. Words can only go so far.

 

If I understand this right, we have two (or more) basically identical subVIs, each non-reentrant, and each used for persistent data storage in several (but different!) instances. For example:

 

Sub_1.vi shares data between locations A, B, C

Sub_2.vI shares data between locations D, E

 

What is the "data"? Do all have the same size and datatype? (e.g. a 1D array of fixed size?)

 

One possibility would be to have inputs for "data_in", "mode (init, read, write)", "set#" and an output for "data_out", then use a 2D array in a shift register where rows are overwritten or read based on the "set#" input. In init mode, the "set#" input could be overloaded as "max# of sets".

 

We could have also an error out to e.g. indicate that the data is valid (e.g. has ever been written). Even if the array sizes of each set differ, there are ways to program around it.

0 Kudos
Message 16 of 23
(754 Views)

Hi.  Thanks you all.

WRT to altenbach,  yes, I do have a program like;

pushkin_0-1642721812517.png                 pushkin_1-1642722568341.png

 

 

I understand (now) that because I wish to use it in different locations with different actions (to Init), that it must be non-reentrant.

 

Another aspect is that I have a dual usage (i.e. Buffer1 and Buffer2) which are exactly the same code.

So how best do you cope with this (outside of my initial suggestion) with LabVIEW

environment ?

 

Regards JC...... 

 

 

0 Kudos
Message 17 of 23
(732 Views)

Hi Pushkin,

 


@pushkin wrote:

Another aspect is that I have a dual usage (i.e. Buffer1 and Buffer2) which are exactly the same code.

So how best do you cope with this (outside of my initial suggestion) with LabVIEW

environment ?


As has been said before: you may use your current FGV approach, but add one more parameter to indicate the index of the buffer you want to access when calling the FGV. The FGV internally handles more than one buffer…

 

On your image:

  • That buffer only has inputs: how do you get data out of your buffer?
  • Ever thought about using clusters to bundle related items (and to minimize connector pane usage)?
Best regards,
GerdW


using LV2016/2019/2021 on Win10/11+cRIO, TestStand2016/2019
Message 18 of 23
(720 Views)

On your image:
  • That buffer only has inputs: how do you get data out of your buffer?
  • Ever thought about using clusters to bundle related items (and to minimize connector pane usage)?

Sorry, it's a work in progress.  The non-clustering I though would be quicker.  I am looking for speed.

 

WRT the subject.  I suspect I was looking for something similar to the macro expansion that you have with say "C".  You have a section of code that gets expanded out into the multiple areas within the project.  This happens before the main compiler.   It simply appears this is not possible with LabVIEW.

 

Regards JC....

0 Kudos
Message 19 of 23
(695 Views)
Solution
Accepted by topic author pushkin

@pushkin wrote:

WRT the subject.  I suspect I was looking for something similar to the macro expansion that you have with say "C".  You have a section of code that gets expanded out into the multiple areas within the project.  This happens before the main compiler.   It simply appears this is not possible with LabVIEW.


I'm not sure how this has anything to do with what was discussed so far. It seems to me that you wanted to have multiple identifiable copies of an FGV. I'm not sure how something like macros would relate to that. In general, I would suggest not trying to outsmart the compiler and not to do premature optimizations, if that's your goal. Just focus on getting readable, useful code.

 

As a side note, I expect inlining VIs is fairly similar to macros in practical terms, in the sense that it's supposed to place the subVI's code into the calling VI's code, but I don't think it would work with an FGV.

 

 

As for your original request, I would suggest using a class (or a library with a cluster), as that would allow you to separate your actions into clear separate VIs. Within this class, each VI should get an identifier for the particular copy (a number, a string, etc.) and start by calling a VI which will get a unique reference for that identifier (I prefer DVRs, but you could also use the single element queue mentioned earlier, which is an older design doing essentially the same thing). You can then have your specific object in that DVR, lock it using an inplace element structure, do your specific operation and unlock it. This guarantees only a single place works on the data at any one point in time.

 

Something like this for performing an action on data 1:

 

Example_VI_BD.png

 

A couple of notes:

 

  1. This assumes that you really do want to work on things by name. Another option for something like this is to create the reference in one place and pass it around as an input to the VIs in the class (or have the class VIs operate by value and wrap the calls to them in an inplace structure, or do the whole thing by value and use actors and messages, etc., but I'm trying not to stray too far from where you are).
  2. Use whichever mechanism you prefer to handle the list of references (for example, this could be an FGV).
  3. References are owned by the hierarchy they were originally created in (which is defined by the top level VI). If you have dynamically called VIs, you would want to make sure you first call all of these in a piece of code that will stay running for as long as these are relevant.
  4. Each of the VIs can have any kind of reentrancy, as the locking is done inside, but the list handler should be global.
  5. Make sure you don't nest these calls, as if you try to call one VI working on your data inside another one, you'll get a deadlock, as they will be waiting on each other to lock/unlock the data.

 

 

P.S. You could also use dynamically created copies of your FGV and call them by reference. This would require you to create a wrapper for your FGV which has an additional name input and that wrapper will handle generating and getting the references and then calling the FGV by reference. This VI could be non-reentrant or it could be reentrant and then it would need to use some kind of global mechanism (e.g. a non-reentrant VI) to get the references.

 

This would probably require the least amount of change to your existing code, but I would not recommend that, because I don't particularly like FGVs if they require you to roll many unrelated actions into the same VI.


___________________
Try to take over the world!
0 Kudos
Message 20 of 23
(679 Views)