Jump to content

strictly typed vi refnum in a class?


Recommended Posts

I am trying to solve a performance problem with my application and I have run into an issue I do not understand.

For some reason, I cannot create a class data element that is a strictly typed vi reference.  I can create a generic one just fine, but if I try to make it strict, I get an error.

 

The reason I am trying to do this is to avoid the overhead and 'root loop' issues with the Open VI Reference call.  In my application I am dynamically launching multiple child objects using a more generic 'handler' VI.  I simply open a reentrant instance of this 'handler' vi, pass in the child class and the 'handler' calls my 'run' method in the child class via dynamic dispatch.  The problem I ran into was the Open VI Reference was bogging down the system.  So, I decided to use the Start Asynchronous Call with options 0x40 and 0x80.  The idea was to open a single reference to my 'handler' when my application starts and then store this in the class data of an object that I pass to all my VIs (for data sharing).  I would then use this reference to call the Start Asynchronous Call function (it requires a strictly typed vi reference).  But, I was stopped when I tried to add the strictly typed vi reference to the class data.

 

As a workaround to prove my fix would solve my speed issue, I created a global variable (horror!) and stored the strictly typed vi reference in that.  I then used this global when calling the Start Asynchronous Call function.  This worked fine and my performance issues are gone.  But I would really like to put that reference in a class instead of in a global.

 

I even tried using a generic vi refnum, thinking I could cast it to the strictly type refnum before sending it to the Start Asynchronous Call but I found that you cannot cast a generic VI refnum to a strictly typed vi refnum.

 

So, any ideas?  This does not seem like a strange thing to want to do.  Perhaps there is some reasoning behind it that I am not aware of.  Any thoughts on a way to accomplish my goal via a different route?

 

thanks for any feedback,

 

-John

  • Like 1
Link to comment

I have a system class wrapped in a DVR that I pass to all processes in my application.  This allows me to create communication channels between these processes (ie: a message system) and limit it to only the processes that I pass this DVR to.  If I want to have two parallel systems, I just create two instances of the system class and wrap each of them in a DVR and pass it to the proper processes.  This allows me to segment my system into multiple independent systems within one application instance.  If I was to use a functional global as you suggest, I would be limited to a single 'system' within the application instance.  (same as the current 'global' I am using)

Now, this does not matter as much if all the 'hander' VIs are based on the same reentrant VI, but it does come into play when I call my system cleanup code.  I cannot put the close reference in there if I have multiple 'systems' within a single application instance with different lifetimes.  Otherwise, I would 'clean up' the reference when one system was shutdown, even though the other system was still running.

 

I also wonder about the pool of shared clones.  It might be more efficient to have each system create its own reference to use when dynamically launching processes because it might mean LabVIEW creates a separate pool of clones for each reference.  But that is getting a bit more under the hood and we will need to hear from AQ or others about the reality of that situation.

Link to comment

I wouldn't expect it to matter for reference types (and if it does I'd expect it's a bug) but may some form of recursion be biting you?

I know you can definitely put a strict VI refnum in a class under normal circumstances, I've done so before.

Link to comment

Figured it out.  My 'handler' VI has an input of type 'system class' and I was trying to add the strictly typed refnum of the handler to that 'system class'.  Looks like I will have to find an acceptable hack to fix this.  I am thinking of passing the class to the handler as a generic reference and then casting it in the handler to the proper type.  Any better ideas?

Link to comment
I am thinking of passing the class to the handler as a generic reference and then casting it in the handler to the proper type.  Any better ideas?

You mean using LVObject?  You should also consider if it is worth having an abstract parent “system” class, and then have the ‘handler’ VI (I use the terminology “shell”, as in “async launch shell”, BTW) be in a child system class.  More work but could be more flexible later on.

 

BTW, if/when you get to benchmarking launch times of your handlers, can you try the following: on the first use of a handler clone (when the overhead of creation happens) try it with the handler being part of a class library, and then not part of a class library.  I found with my code that it was about four times slower if in a class library.  If I recall right, I got initial creation times on the order of a couple of milliseconds if it isn’t in a class and 8 ms if it is (reuse of an existing clone was much faster, something like a 0.2 milliseconds).

Link to comment

My handler VI is not in a class, but it is in a library.

I have already made some child classes of my system that enable additional features, like networked messaging.  I suppose I could add a new child for dynamic launching, but that would mean that the networked enabled system class would need to inherit from the dynamic launching system class.  Should would be nice to have multiple inheritance for this situation.

Also, I consider the dynamic launching feature to be a core feature of the system so I would prefer to have it in the top parent.  I don't like adding complexity if I can avoid it.  But, this might be the only solution.  So far, it does not look like I can cast a generic DVR ref to a specific DVR ref.

Link to comment

Solved it with a variant.  I changed the system class DVR input in the handler to a variant and then cast it to the proper type within the handler.  Now the system class is happy to have the strictly typed vi ref of the handler in its private data.

I also added a test to the handler launcher that checks the stored ref and creates a new one if it is invalid.  I wrapped this in an IPE structure to prevent multiple callers from updating this ref at the same time.  I suppose that is not absolutely necessary since the ref is to the same VI type, but this prevents me from leaking references if two get opened at the same time and I only store (and clean up) the last one.

I see that AF does something similar except there the launcher is non-reentrant and the ref is stored in an uninitialized shift register.  Personally, I am not a big fan of non-reentrant code.  I only use that setting in specific cases (like FGVs) and tend to make all my other VIs shared clones.  I wish I could set that to be the default when creating a new VI...

 

Now, for each concrete instance of my system class that uses dynamic process (actor) launching, I get a separate VI ref to the handler.  I wonder if this creates a separate pool of shared clones?  And if so, I wonder if this improves or degrades performance?

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.