LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

It's impossible, but it happens.

Solved!
Go to solution

CoastalMaineBird wrote:

This is why you should handle errors and if you don't, have automatic error handling on.

 

But, but, but, it can't possibly have an error there ! (How many times have you heard that?)


Enough times to stick to rule of "handle errors one way or another", which actually hurt me once where someone asked me to debug some code which had auto error handling disabled, but I was expecting it to be enabled. It didn't help that the specific function was also returning a meaningful value, so I assumed that definitely means it doesn't return an error.


___________________
Try to take over the world!
Message 21 of 26
(943 Views)

@CoastalMaineBird wrote:

A reference is owned by the the hierarchy it was created in. 

 

It makes no sense to me WHY that would be the case


I expect that this was either done for practical reasons (it's easier to remember a single owner than to do ref counting) or because it was deemed to be a clever piece of design meant to make cleanup easy. I can think of ways where you can use this if you know how it behaves and I know of good programmers who do.

 

Technically, I don't think there's any reason why NI can't change it so that the cleanup only happens when all callers go idle, but it requires actually doing the work.

 

As a side point of this, it's important to be aware that this rule applies to references. If you opened multiple references to the same queue, one in each block, the queue would not be destroyed until all of its references were destroyed and you wouldn't have had this problem either (not that I'm advocating that as a solution. I'm not a big fan of named queues).


___________________
Try to take over the world!
Message 22 of 26
(935 Views)

It now reliably closes down in < 300 mSec, and starts up in about 3 sec, since I put a copy of the queue VI in the main app VI.

 

My thinking was that the functional global I created would "own" the queue, since it created it.

That is certainly true for a number or a string, if I create those and store in a shift register, then they exist as long as that VI does.

Therefore, as long as the MM STOP vi was not actually unloaded, the queue would still exist.  

 

But, apparently references are different.

 

I would assume that applies to ANY reference (Rendezvous, VI ref, etc) ?

 

 

TO RECAP:

 

The first call was made by block #0, shortly after it launched.  That created the queue.

 

When shutting down, the event is broadcast, but who sees it first, and who reacts first is a matter of chance.  But at some point, block #0 (the "owner") reacts, pulls an item out of the queue (to signify its own demise) and quits.

 

THAT KILLS THE QUEUE.

 

The other instances try to dequeue an element from the now non-existent queue and fail.

 

The container window, not catching the error, saw a 0 result, and thought the queue was empty.

 

All of that explains the "impossible" part: why the queue showed up empty before the messages were logged.

 

Not sure I understand why it would be slowing things down, though. But that does seem to be fixed as well.

 

Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


Blog for (mostly LabVIEW) programmers: Tips And Tricks

0 Kudos
Message 23 of 26
(934 Views)

you should change from using VI Path to VI Name in your launcher code so that it uses the copy in memory (from the static VI reference) rather than trying to load it from disk.

 

I didn't actually time it down to the mSec, but it didn't make a noticable difference.

Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


Blog for (mostly LabVIEW) programmers: Tips And Tricks

0 Kudos
Message 24 of 26
(934 Views)

In your launcher I saw two for loops with 999 wired to the first loop iteration count and 999 wired to the second loop. The second opens a VI reference from disk and runs it. Hence the ~1 million openings/runnings.

Admittedly, I hadn't noticed the indexing terminals for the tab pages / controls on page.

As for the path/versus name - I found out that loading a VI from disk happens in the 'root loop' / UI thread and so can be blocking to other areas of the application. Since you have a Static VI reference, the VI is already loaded into memory so you can just use the 'Name' property of the VI reference to launch it without having to access the disk. The best example of this is how VIs are launched in the actor framework. (Someone made an interesting blog post about this and but I can't find it right now)

 

Edit: Nevermind - I found it: http://www.labviewcraftsmen.com/blog/the-root-loop here is the point I picked up on:

 

"If you wire a path, LabVIEW waits until the user interface is idle to load the VI from disk. If you wire a name string, LabVIEW does not need to wait until the user interface is idle, as it does not load a VI from disk. LabVIEW will only search in memory for a VI with a specified name."


LabVIEW Champion, CLA, CLED, CTD
(blog)
0 Kudos
Message 25 of 26
(910 Views)

@CoastalMaineBird wrote:

 

My thinking was that the functional global I created would "own" the queue, since it created it.

That is certainly true for a number or a string, if I create those and store in a shift register, then they exist as long as that VI does.

Therefore, as long as the MM STOP vi was not actually unloaded, the queue would still exist.  

 

But, apparently references are different.

 

I would assume that applies to ANY reference (Rendezvous, VI ref, etc) ? 


Basically yes. And not just green refnums but also those purple "named references" (IMAQ, VISA, DAQmx, etc.). With one exception, you can change in the Option dialog if VISA refnums should be destroyed automatically.

 

As has been already mentioned, it is one way of trying to do resource management. It is simpler than refcounting and works in many cases better but it is something one has to be aware of. It starts to break when using architectures where you startup multiple independent top level hierarchies who all try to work on the same resources. Refcounting while able to overcome this problem, are much more complicated and tend to often remain with one refcount somewhere hanging in the air and keeping the object alive, making the whole purpose of refcounting highly useless. Refcounting works well when the programmer is actively required to indicate when a resource is not required anymore but causes all kinds of problems when applied to a data flow controlled system. That untinialized shift register (or feedback node) can't really know if the system isn't going to execute the code again, somewhere, somehow, sometimes. Refcounting would require to reinitialize each and every such element as well as global and local variables with the default Not A Refnum value in order to really release the associated object. Not very practical really.

Rolf Kalbermatter
My Blog
Message 26 of 26
(857 Views)