Jump to content

Self-Persistent By-Reference Class Instance


Recommended Posts

I've created a by-reference framework similar to the Extensible Session Framework (https://decibel.ni.com/content/docs/DOC-12813), with the difference that my object references are self-persistent. This is achieved by creating the object instance in a separate thread, which remains running in the background. This is all working rather smoothly, but I would like to clean up my code a bit.

 

Right now, I have a Persistent Object root class which contains only two properties (Instance Name and Destroy Event) and two methods (Create and Destroy). A child class overrides the Create and Destoy methods, and offers class-specific functionality. Unfortunately, the child class also contains the wizardry code that maintains a list of existing instances and manages the creation / destruction of particular instances. I've included some snippets that demonstrate these methods, as well as a typical top-level vi.

 

Example top-level vi:

post-51929-0-16187100-1413893048.png

 

Require method:

post-51929-0-11892400-1413893051_thumb.p

 

Unrequire method:

post-51929-0-99942100-1413893052_thumb.p

 

Holder method:

post-51929-0-25618200-1413893049_thumb.p

 

Of course, the framework-related functions should preferably be in the root class, not in this child class, to allow me to make changes to the framework without editing all child classes. The problem is that I cannot create the Require/Holder/Unrequire functions in the root class and override them in the child class, as the DVR terminal data types will not match. 

 

Does anyone see an elegant solution to this problem? Thank you.

Link to comment

This is a common issue when working with by-ref objects. The way I solve it is by making static VI called things like "MyAction" and then making a Dynamic dispatch VI named "MyAction-core". All "MyAction" does is de-reference the object, call "myAction-core" and then updates the DVR value.

 

post-27575-0-98006100-1413906609_thumb.p

 

Also, if these are actions that HAVE to be performed, I'd just throw the common code in "MyAction", and then let the children override "MyAction-core" to implement the code that's specific to them. This eliminates the need for children to call to parent. I'm not a big fan of requiring a call to parent, because I find most of the time it matters if the child calls to parent before or after running it's code. So you end up having to put in documentation "Make sure the first thing your child code does is call to parent". This is bad.

 

Basically what I'm saying is a lot of time when people (and I think you in this case) are checking the "Require Call to parent", what they really want is a Template Method pattern.

 

http://en.wikipedia.org/wiki/Template_method_pattern

post-27575-0-98006100-1413906609_thumb.p

  • Like 1
Link to comment

All I can add to this is that QueueYueue's suggestion is exactly how I resolve similar issues in my frameworks without resorting to other class creation frameworks such as GOOP or G#. Let dynamic dispatch work it's magic on object terminals and let the root class be by-reference.

 

The ESF has the same issue you are experiencing but it has that nifty class creation utility to hide the busy work.

Edited by ak_nz
Link to comment

How does this affect persistence though? If I spawn the Holder thread in the root class and create the DVR in the child class, the ownership of the DVR (and other child-specific init code) lies with the calling vi. LabVIEW will clear those references when the first calling vi leaves memory, whereas other VIs might still need access to the object.

Edited by abrink
Link to comment

If one needs a persistent reference, not tied to the lifetime of one VI hierarchy, then one can either:

1) Async Call a VI to create and own the reference as brink is doing.

or 2) Use a Named Single-Element Queue with multiple references instead of a DVR to hold the session data.

-- James

BTW: If I were designing a persistent session framework I would probably combine both, in order to get around their individual weaknesses:

(1) can't handle VIs that forget to call the Close Session method, in violation of LabVIEW's standard "refs don't outlive their creator" rule.

(2) can't execute cleanup code, as the data in the SEQ is just dropped.

Edited by drjdpowell
Fix unicode corrupted characters
Link to comment

FYI,

ESF 3.0 is in the tubes and about to come out w/ the ESFx with the persistent ability option.

 

It will not be forced but seamlessly worked into the framework because not everyone will want a sub-process running in the background and there is no way to make it perfect.

 

We're using it internally and hopefully getting this out the door can prevent another framework doing the same thing.

 

Please let me know if you are ready to beta test the new version.

 

Thanks,
Norm

~,~

  • Like 1
Link to comment

How does this affect persistence though? If I spawn the Holder thread in the root class and create the DVR in the child class, the ownership of the DVR (and other child-specific init code) lies with the calling vi. LabVIEW will clear those references when the first calling vi leaves memory, whereas other VIs might still need access to the object.

 

1. The DVR is created in the parent's code because creating the DVR is part of the common code. For the most part, the child should never have to deal with DVRs. The parent class does all the DVR related tasks.

 

2. Even if the child creates the DVR, the reference's lifetime is tied to the top level VI that created it. You're going to still have to use an Async Call VI method (which will at some point call the create DVR method), so that's what will control the lifetime of the reference.

Link to comment

Even if the child creates the DVR, the reference's lifetime is tied to the top level VI that created it. You're going to still have to use an Async Call VI method (which will at some point call the create DVR method), so that's what will control the lifetime of the reference.

If one uses a named single-element queue, instead of a DVR, then one can get the lifetime of the queue to exceed that of its initial creator.  This is because one can create multiple references to it; the queue continues to exist till all references to it are released.

Link to comment

Unfortunately, a SEQ doesn't solve anything. Any references within the object (events, etc.) are released when the first caller leaves memory, so you'll end up with a useless object in the SEQ.

QueueYueue, I fully agree with your first point, but this construction is impossible as I explained before. A root class cannot create a DVR to a child class. Hence my call for a Dynamic Dispatch DVR terminal type, which I'll file shortly.

Link to comment

QueueYueue, I fully agree with your first point, but this construction is impossible as I explained before. A root class cannot create a DVR to a child class. Hence my call for a Dynamic Dispatch DVR terminal type, which I'll file shortly.

 

Yes you can. You just have to use a template method pattern

 

AQ has written a lot of good info here about why you can't (and wont be able to in the near future) have dynamic dispatch DVR terminals http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Have-Dynamic-Dispatching-terminals-accept-Data-Value-references/idi-p/1054410

ParentChild DVR.zip

Edited by QueueYueue
Link to comment
  • 8 years later...
On 10/22/2014 at 11:52 AM, Norm Kirchner said:

FYI,

ESF 3.0 is in the tubes and about to come out w/ the ESFx with the persistent ability option.

 

It will not be forced but seamlessly worked into the framework because not everyone will want a sub-process running in the background and there is no way to make it perfect.

 

We're using it internally and hopefully getting this out the door can prevent another framework doing the same thing.

 

Please let me know if you are ready to beta test the new version.

 

Thanks,
Norm

~,~

Any update on version 3.0? It’s concerning how long ago v3.0 is mentioned and the latest version I have is 2.4 or something like that. I’m in slight freak out mode as I just spent days writing an API/driver based on ESF and I can envision certain use cases where it would be VERY nice to not have the session handle (for ones that obtained the session after it was created) go invalid when the original vi that creates the session exits.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.