Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Appropriate reentrancy in Message and Actor Core subVIs

Given that Actors are multi-instanceable, are there simple rules of thumb for setting the reentrancy (none, shared, full) of public methods called by Message:Do.vi and methods used in the Actor Core.vi override?

0 Kudos
Message 1 of 26
(16,900 Views)

And an adjunct question: If full reentrancy is used on message methods, then I think those methods can't be allowed to retain state between calls. Is that correct? It seems like I need to cache state in the object wire instead of a SR or FN inside the method, because the same instance of that method isn't guaranteed to be used by the next received message.

0 Kudos
Message 2 of 26
(4,769 Views)

For debugging purposes, I find it easier to disable re-entrancy.  If this is not possible, then I generally launch the Actor core's front panel and "Step Into" the methods of interest.

DavidStaab wrote:

And an adjunct question: If full reentrancy is used on message methods, then I think those methods can't be allowed to retain state between calls. Is that correct? It seems like I need to cache state in the object wire instead of a SR or FN inside the method, because the same instance of that method isn't guaranteed to be used by the next received message.

Yes, feedback nodes/uninitialized shift registers become evil.  All "flags" should go in the private class data.

CLA, CTA
0 Kudos
Message 3 of 26
(4,769 Views)

Hi LVB,

Could you expand on how you launch the Actor Core's front panel (and if the method will work in a RT environment running in development mode) and then how you "Step Into" the methods?

Cheers

0 Kudos
Message 4 of 26
(4,769 Views)

To show the actor core front panel:

  • For 3.x, use the LabVIEW Task Manager
  • For 4.x framework, there is a boolean input to launch actor that allows showing the front panel of the Actor Core QDSM.  I usually wrap that in a conditional disable structure and set project flags.

You can create a custom probe to check the message type in the Actor Core and break on the name.  Then use the Operate -> Step Into (CTRL+DOWN) to open the Do.vi method that is dynamically dispatched and the associated Actor class method.  Note: This is on a windows desktop, not a RT system.

CLA, CTA
0 Kudos
Message 5 of 26
(4,769 Views)

Debugging functional logic isn't an issue here. I develop my classes for static operation first, test them, then wrap them in AC.vi and Do.vi. This lets me debug using the native LV tools with statically linked code.

The issue is that I wrote this huge class using a lot of stateful subVIs, and only when I moved to a multi-instance testbench did I realize the mistake. I'm going through the class and setting reentrancy on all its methods (which led to the first question about which type of reentrancy to use in each situation), and I realized that I'm going to have to move all that stored state out to the class's scope in order to make it work correctly.

The longer I write software, the more I become convinced that internal storage of any state is a generally terrible idea. Scope it privately it and push it all up to the caller for storage!

0 Kudos
Message 6 of 26
(4,769 Views)

I think the re-entrancy decision is the same with or without the Actor Framework.

The rule of thumb I use for re-entrancy is the KISS principle.  If I don't need the performance or am not concerned about "blocking" methods, then I don't make it re-entrant.  One nice "feature" of a non-reentrant VI is the developer will know that no other Actor can be executing the method (psuedo locking/mutex).

CLA, CTA
0 Kudos
Message 7 of 26
(4,769 Views)

If you write an Actor, you have to assume it's going to be multi-instanced. If you want to prevent that, the only way to do it is with a run-time check that throws an error when the second instance is launched.

In my specific use case, I need exactly 4 instances of this actor now and up to 16 later. So I'm stuck working with reentrancy. (For those following along, my original post about defining rules of thumb is still unanswered.)

0 Kudos
Message 8 of 26
(4,769 Views)

i haven't had time to test this out, but this is the approach i was planning to use when i go to the AF.

for initialization & shutdown VIs, make them non-reentrant. performance shouldn't be as critical here. i typically launch all of my dynamic stuff in a serial manner and this jives with that.

for message and core VIs, make them reentrant with shared clones. it should be efficient in a single instance and scale up when you need it.

of course, the above approach doesn't make any considerations for ease of debugging...my plan there was to change them over as needed during the debug process.

0 Kudos
Message 9 of 26
(4,769 Views)

The guidance for which methods to make which kind of reentrancy is the same as for any other VI. There is no difference.

Non-reentrant: By far the most common setting for VIs. Use this for functions that

  • have state that you need to be shared by all callers OR
  • that are only called by one caller OR
  • if called by multiple callers you don't mind if the calls serialize (for rarely sent messages, the probabability of two actors needing the same function at the same moment may be very small, and even if they do collide, most message handling functions tend to be small as actors tend to prefer not holding up their own message handling loop)

Full reentrant: Use this for functions that

  • Have state specific to each caller that needs to be remembered call after call (like point by point averages) OR
  • Have multiple callers that could call simultaneously and need maximum performance at the cost of maximum memory usage

Shared reentrant: Also known as pooled reentrant because clones are in a common pool. Use this for functions that:

  • Are completely stateless AND
  • Need to use less memory than full reentrancy with a small cost amortized over many calls. This is the preferred form of reentrancy to use on the desktop systems as the performance trade off is negligible and the memory savings is substantial. I believe the same recomendation holds for RT but I am not as knowledgable about those targets.

DavidStaab wrote:

And an adjunct question: If full reentrancy is used on message methods, then I think those methods can't be allowed to retain state between calls. Is that correct? It seems like I need to cache state in the object wire instead of a SR or FN inside the method, because the same instance of that method isn't guaranteed to be used by the next received message.

Shared reentrancy is the one that cannot have state. Full reentrancy can have state because every subVI node will get the same instance every time it is called. It cannot have *shared* state -- shared state is for non-reentrant VIs.

Message 10 of 26
(4,769 Views)