LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

A plane English guide to reentrancy settings? Considerations, impact, consequences, pros/cons.

Every time I File>New VI knowing that the VI I’m about to make can or may be must, be reentrant, I find myself hemming and hawing over what to do at the selection screen in the vi properties. I understand the basics between non-reentrant and reentrant, and even the basic gist between shared and pre-allocated, but I definitely don’t know which is best to pick each time or all the detailed consequences of each.

 

 

For instance, let’s say a certain subvi is a very simple concatenation, array operation, or mathematical operations. And suppose this will be needed in numerous places all over the program, called by various non-reentrant parents. My first instinct would be to preallocate and check the inline box too. There might even be a good argument against reentrancy if performance is not critical.

 

 

Now let’s say the vi I wish to make reentrant is something I want to call via Run vi, call asynchronous, etc. Here’s where things break down for me. There are numerous combinations of reentrant call options and I think they matter depending on which reentrant box you’ve checked but I don’t know all the particulars. I generally choose shared clone when I don’t know how many clones to expect at runtime. Is that the ultimate criteria? What are the consequences of preallocated clones called in this way? Which prepare reentrant calls work for which reentrancy type? Is it possible for a calling vi to access a specific clone via its reference with both types? 

would also love some rules of thumb for when and why to inline a subvi.

Message 1 of 6
(745 Views)

@DoctorAutomatic wrote:

Every time I File>New VI knowing that the VI I’m about to make can or may be must, be reentrant, I find myself hemming and hawing over what to do at the selection screen in the vi properties. I understand the basics between non-reentrant and reentrant, and even the basic gist between shared and pre-allocated, but I definitely don’t know which is best to pick each time or all the detailed consequences of each.

 

 

For instance, let’s say a certain subvi is a very simple concatenation, array operation, or mathematical operations. And suppose this will be needed in numerous places all over the program, called by various non-reentrant parents. My first instinct would be to preallocate and check the inline box too. There might even be a good argument against reentrancy if performance is not critical.

 

 

Now let’s say the vi I wish to make reentrant is something I want to call via Run vi, call asynchronous, etc. Here’s where things break down for me. There are numerous combinations of reentrant call options and I think they matter depending on which reentrant box you’ve checked but I don’t know all the particulars. I generally choose shared clone when I don’t know how many clones to expect at runtime. Is that the ultimate criteria? What are the consequences of preallocated clones called in this way? Which prepare reentrant calls work for which reentrancy type? Is it possible for a calling vi to access a specific clone via its reference with both types? 

would also love some rules of thumb for when and why to inline a subvi.


Good questions!  I am going to participate in this topic as a learner.

Bill
CLD
(Mid-Level minion.)
My support system ensures that I don't look totally incompetent.
Proud to say that I've progressed beyond knowing just enough to be dangerous. I now know enough to know that I have no clue about anything at all.
Humble author of the CLAD Nugget.
0 Kudos
Message 2 of 6
(714 Views)

This is a good question that is not getting much discussion in the forum so instead of a direct answer I have some thoughts.  I think this is a good place to start (from the labview wiki: https://labviewwiki.org/wiki/Reentrant_VI)

 

 

Reentrancy Compared to other Languages

To expand on this, reentrant means that more than one execution is allowed to take place at the same time. In other languages, it is more a situation than a setting. You never mark a C function as allowing or disallowing reentrancy, it is either safe to do so or a source of bugs. In LabVIEW it is a setting, and many times its setting doesn't affect the correctness of a VI, but in some cases, it can be a source of bugs. It depends on what the VI does.

 

In particular the part about correctness is interesting, as in there is not a correct way there is only a way that does not cause bugs : )

__________________________________________

 

I have a thought process for selecting re-entrant VIs that goes like this, not saying it is correct, just getting the conversation going: 

 

1) Will it be called recursively? if yes its re-entrant , try pre-allocate

 

2) will it be called recursively in a loop? if yes its re-entrant , try pre-allocate 

 

3) is it a .vit that will need a few instances? if yes its re-entrant, try shared

 

4) is it an actor? don't worry about it 

 

I read somewhere that you can only have the number of shared clones per the number of processors you have on your machined, or that is what think I remember about that. 

 

I guess 'pre allocate' and 'shared' are compiler instructions that gets down into C/C++ land and can choose to either execute the 'VI' in an concurrent thread or another process. 

 

Perhaps that is a way to think about it, if you need to run re-entrant code in parallel, it's better to be shared, if you have recursive calls, you cant run it in parallel so its better to pre-allocate. 

 

I think 'shared' is bad terminology for a VI because it makes me think shared memory space, which might be true for the instructions but probably not for the state. 

 

 

______________________________________________________________
Have a pleasant day and be sure to learn Python for success and prosperity.
0 Kudos
Message 3 of 6
(631 Views)

I (slightly) beg to differ (based on several "things which worked for me" examples).

  • If it is "simple recursion", for example, breaking a U32 into a series of digits (12345678 becoming either [1, 2, 3, 4, 5, 6, 7, 8] or [8, 7, 6, 5, 4, 3, 2, 1]) can be coded as a recursive routine.
    • DigitsMSD takes U32 and returns Array[SingleDigit] with MSDigit first, or
    • DigitsLSD takes U32 and returns Array[SingleDigit] with LSDigit first.
  • In this case, Shared clone reentrant recursion is appropriate.  Clones are allocated "as required" and only a finite number (essentially one per digit of the largest number called) will be needed.
  • On the other hand, if you are creating an "Array of detached clones" because you want to process "parallel loops for an N-channel Task", that requires clones that are "Preallocated clone reentrant execution", precisely because no recursion is involved, so you want to allocate a dedicated clone that will be associated with the particular instance of the detached parallel process.  It is reentrant, but not recursive.

I've written routines that did recursion, and that did parallel detached clones.  I thought I had more examples where I used recursion, but I'm at NI Connect, and can only look at a subset of my LabVIEW "old stuff" and can't find my other "clever" recursive routines (like quickly and efficiently calculating binomial coefficients, which I have somewhere ...).

 

Bob Schor 

Message 4 of 6
(619 Views)

Hi

 

NI has made a pretty detailed explanation for how to manage reentrancy.

 

See this :

 

https://www.ni.com/docs/en-US/bundle/labview/page/lvconcepts/reentrancy.html

 

Regards

 

Message 5 of 6
(611 Views)

Hi again

 

NI moves everything to their web site manual and timestamp it as new ( 2023 ).

 

The web version is lifted from a help file named lvconcepts.chm, included with every LabVIEW release, at least since 2010 and maybe even before that.

 

The content of this help file has changed over time. So looking into older versions of that file may give additional insight angles into the subject.

 

I prefer the older CHM versions. They look better.

 

Regards

0 Kudos
Message 6 of 6
(585 Views)