LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Excuse my ignorance! How do you put a queue inside a refnum?

Solved!
Go to solution

I found this example code below and I was wondering how you do that. Also what exactly does it mean when a queue is inside a refnum as shown below

GRCK5000_0-1665761314577.png

GRCK5000_1-1665761335831.png

 

~ I learn by asking questions 😁 ~

 

 

0 Kudos
Message 1 of 10
(2,358 Views)

To the question of "How"... the data size in memory of a reference and a queue wire is the same (4 bytes). Type cast doesn't change that data, just reinterprets it... so when the queue is type cast to a refnum it retains the data. The fact that it is a "refnum" is inconsequential. One could type cast it to a U16, string, byte array etc.  For example:

 

BowenM_0-1665763121652.png

 

executes just fine.

 

Now that we have "how" covered, we come across the question of "why?"  I can't think of a single reason to type cast a queue handle into a reference.

Whatever the developer in the example you were following was trying to accomplish by type casting a queue reference, I guarantee there is a better way to accomplish the same task that doesn't leave fragile code.

 

 

Edit:
I looked at your screenshot again and realized it was labeled "config refnum" and it triggered a memory... and I remembered that the NI_LVConfig library does exactly this. I suspect the example you were following was interacting with the NI_LVConfig library.

 

The only reason(s) I can' think that NI chose to do this for the library this were:

1. It was implemented before LVOOP and was done as an attempt to keep data private.

2. Type cast to a ref in order to make it "look" like a standard file reference.

 

Both of these tasks can be accomplished better using LVOOP... so again I see no reason to do this. Maybe someone will come along and show me how I'm wrong 🙂

0 Kudos
Message 2 of 10
(2,341 Views)

If you look in NI's own code for both the "Semaphore" and the "Config file"  (and possibly some others) they both do this, so the "why" could be as simple as "they were copying NI".

 

As for why NI did it, I would venture it was partly because they did this in the days before LVOOP and the notion of class wires and protected data inside them was available to LabVIEW. If you need to pass a queue around that shouldn't be treated like a queue by the user because it's supposed to be used only in very specific ways, making it "look" like another type of wire is an effective method of doing so.

 

Having a queue with a single element in it is a way to make an inherently parallel environment like LabVIEW have a way to force certain operations to only run one at a time, since whichever section of code successfully dequeues the single element now has exclusive access to it.  It's another bit of functionality alongside the DVR reference method and the FGV method for ensuring that no race conditions can apply to a set of data while it's being modified.

0 Kudos
Message 3 of 10
(2,329 Views)
Solution
Accepted by topic author GRCK5000

I've never seen that done before personally. Where'd you get that code?

 

Pure speculation:

 

Refnums are just references to some other "thing". It could be a reference to a file that's open, or to an image, or whatever. Refnums are one way that LabVIEW does "by-ref" code.

 

In other words, normally the wire IS the variable. If you have a wire with a U32 value of 17 on it, then split the wire and add 1 to one wire then that wire becomes 18, but the other wire stays as 17. This is what's called "by-value".

 

A slightly more involved way to think about it is to say you have a function that takes an integer and adds 1 to it. When you give that function a wire with 17 on it, it takes the value of the wire and adds 1 to it, and returns a new value of 18. The old variable value of 17 may still exist if the wire was split. In other words, the function acts on the value provided to it.

 

This is in contrast to a function that operates by reference. If you open a file to write to it and write "Hello World", then split the refnum to one function that adds "I love hot dogs" to the file and another that adds "I love salads" to the referenced file, you wind up with one single file that has ALL of the text in it. Despite splitting the wire, you don't end up with one file that says "Hello World I love hot dogs" and one that says "Hello World I love salads", you just have one single "Hello World I love hot dogs I love salads".

 

In other words, the function is operating on the reference to the file, not the value of the file. I hope that makes sense because it's background to the "why" of your code.

 

LabVIEW is 95% by-value coding. Notable exceptions are aforementioned file refnums as well as all of the VI Server refnums that let you access other VI's, front panel elements, block diagram elements, etc. DAQmx also uses references, but they're not "refnum" datatypes they're a special DAQmx datatype. Queues and events use refnums as well.

 

When you give a function a file refnum, it does some behind the scenes wizardry to get the right file info to be able to write to or read from the file.

 

What I think your code here is doing is implementing its own refnum to create custom by-ref functionality. You see, a single element queue is another way to implement by-ref data handling, since no matter which function calls it you know you're getting the same "thing" behind the scenes. Splitting a queue wire doesn't duplicate the queue, it lets multiple parts of your code access the SAME queue.

 

All of that is fine, but the problem comes when you need your code to be used by others. Exposing the queue to other functions will make other people think they need to use queue functions to interact with it. Imagine if your "Write to File" function had a "File queue" input- that might work, but it would be confusing, since it's not actually a queue that writes to a file but a queue that contains a single element reference to the file stream.

 

So how do you implement by-ref functionality without giving users a queue? By putting a nice Halloween mask on top of the queue reference! Your code there has a typedef'd "config refnum" datatype that your function expects. At some point, that queue is created, then is cast to a typecast special config refnum that no other function ever knows how to handle *other than* the library that created it. This means that no other functions can mess around with the internal queue. Your function here does the reverse, turning it back into a queue that can be used to pull out some other information.

 

Basically, you're not exactly "putting a queue inside a refnum"- you're disguising a queue AS a refnum, since under the hood queues are special references anyway.

 

I would suggest NOT messing with any of the code that's doing those things. There are lots of things to consider about arbitrarily typecasting a queue into a refnum, such as making sure you're not losing any bytes, making sure LabVIEW knows the queue is still valid, and so on. Doing some Googling it appears that this technique was popular at least as far back as LabVIEW 7.0. Nowadays, if I wanted to do something like this I'd wrap it in an object, not rearrange the puzzle pieces to make it look like another datatype. I'm sure this method works just fine and is probably super fast and low on memory usage, but if LabVIEW ever changes the internals of what a Queue reference contains, then this type of code could break.

Message 4 of 10
(2,325 Views)

@BertMcMahan  a écrit :

I've never seen that done before personally. Where'd you get that code?


I've seen this code recently in an answer from paul_cardinale:

https://forums.ni.com/t5/LabVIEW/Refnum-to-Path-odd-behaviour/td-p/4260922

0 Kudos
Message 5 of 10
(2,281 Views)

@raphschru wrote:

@BertMcMahan  a écrit :

I've never seen that done before personally. Where'd you get that code?


I've seen this code recently in an answer from paul_cardinale:

https://forums.ni.com/t5/LabVIEW/Refnum-to-Path-odd-behaviour/td-p/4260922


Yeah, that's mine.  LabVIEW uses a queue as a buffer to store the contents of config files.  A config file reference is really a reference to the queue.  As to why they did it like that, i haven't a clue.

"If you weren't supposed to push it, it wouldn't be a button."
Message 6 of 10
(2,248 Views)

You are the best. You really take your time to answer questions. Great answer and explanation. Even if your answer was wrong, I would just pick it as solution because you're doing a lot of sacrifice writing all these answers. This is not the first time I see you answering. 

Wow! what a great person!!! Sharing as much knowledge as you can. Impressive!

0 Kudos
Message 7 of 10
(2,243 Views)

BertMcMahan_0-1665777819627.gif

 

0 Kudos
Message 8 of 10
(2,236 Views)

Actually all the refnums like file refnums, network refnums, queues, notifiers, DAQmx refnums, IMAQ refnums etc, etc use the same basic refnum type underneath, a 32 bit integer magic cookie that identifies the storage slot for that refnum type in question where LabVIEW stores the internal management information for it. The refnums with a string form are simply a special flavor of them that also has an attached string attribute as an alternative form of identifying the refnum. The typecast works because the underlaying datatype always is a 32-bit integer magic cookie.

 

The reason to do it like ghis is to hide the fact that the configuration file really is a single element queue and to prevent normal LabVIEW users to accidentally modify its contents, which would render the config file functions to work incorrectly. And yes those VIs were introduced before LabVIEW had native classes. They used the first iteration of LabVIEW Goop functionality and were rewritten to replace that LabVIEW Goop 1.0 Voodoo code with the newly introduced native queue nodes in 8.0, before LabVIEW got classes.

Rolf Kalbermatter
My Blog
Message 9 of 10
(2,157 Views)

@rolfk wrote:

Actually all the refnums like file refnums, network refnums, queues, notifiers, DAQmx refnums, IMAQ refnums etc, etc use the same basic refnum type underneath, a 32 bit integer magic cookie that identifies the storage slot for that refnum type in question where LabVIEW stores the internal management information for it. The refnums with a string form are simply a special flavor of them that also has an attached string attribute as an alternative form of identifying the refnum. The typecast works because the underlaying datatype always is a 32-bit integer magic cookie.

 

The reason to do it like ghis is to hide the fact that the configuration file really is a single element queue and to prevent normal LabVIEW users to accidentally modify its contents, which would render the config file functions to work incorrectly. And yes those VIs were introduced before LabVIEW had native classes. They used the first iteration of LabVIEW Goop functionality and were rewritten to replace that LabVIEW Goop 1.0 Voodoo code with the newly introduced native queue nodes in 8.0, before LabVIEW got classes.


Thanks for this.  I always had a rudimentary understanding of refnums, but I never did take a peek under the hood to see what was really going on.  This is actually very interesting stuff to me.

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 10 of 10
(2,143 Views)