From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Understaning Semaphore/queue reference memory usage

I'm using semaphores (implemented internally using queues) to protect simultaneous access to instruments. From what I understand, obtaining a reference to a semaphore and not closing it will lead to a memory leak.

 

I have a lockVI which obtains a semaphore reference but does not close it, and an unlockVI which obtains a semaphore reference and closes it. I would like to know if this would cause a leak. The profiler indicates that it does not.

 

test1.jpg

(Note that I'm not passing the semaphore reference from the lock and unlock VI, but relying on the semaphore name)

 

Does labview have a garbage collector which releases the memory in the lockVI? Or does the semaphore reference the lockVI get freed when the semaphore gets deleted in the unlockVI? 

 

If I were to release the semaphore reference in the lockVI, the semaphore would get deleted. Is it possible to clear a semaphore reference without clearing the semaphore itself even if there are no other references existing in memory?

 

Thanks in advance.

 

 

 

 

0 Kudos
Message 1 of 9
(3,096 Views)

If you look "under the hood", semaphore references are actually queue references!

 

And the way queue references work is that LabVIEW drops the queue from memory if either:

1. It "thinks" all VIs that call it are done using it

2. It gets the same number of calls to "release queue" as it does to "obtain queue"

3. "Release queue" is called with the "force destroy" option

 

With the code you have, and NOT passing the semaphore reference, you're calling the "obtain" twice as much as you are "release", so yes, you could have a memory leak unless you start passing the reference or saving the reference somewhere (FGV, global, etc.).

Message 2 of 9
(3,078 Views)

LabVIEW will free the semaphore reference(s) when the top level VI stops (hierarchy is Idle) so until then the references won't be automatically released unless you explicitly do so (via the Release Semaphore Reference VI).

 

That's a named semaphore reference so you're always getting a new reference to the same semaphore instance with Lock and Unlock but only freeing one of those references in Unlock. It will also mess up the ref counting so you don't get automatic semaphore release. Have a read this: https://lavag.org/topic/9722-obtain-queue-memory-leak/.

 

I can see that you are trying to change the syntactic behavior of the usage of the semaphore, presumably so that the caller need not concern itself with the semaphore ref wire. Ironically though you still have a wire involved going to both VIs ("InstAddress") that must contain an identical value so I'm not sure what you are gaining - you would be better off just using the ref wire between the Lock and Unlock VIs.

 

Message 3 of 9
(3,065 Views)

Personally, I am not a fan of Semaphores.  They can be completely avoided by using Action Engines (AE), Queued Message Handlers (QMH), or Data Value References (DVR).

 

As has already been said, you are just reusing the same named queue, so there won't really be a leak until you try to shutdown (reference left open).  But the simple solution is to add to your shutdown code to get a reference to the Semaphore and then close with "Force Destroy" set to TRUE.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 4 of 9
(3,051 Views)

@crossrulz wrote:

Personally, I am not a fan of Semaphores.  They can be completely avoided by using Action Engines (AE), Queued Message Handlers (QMH), or Data Value References (DVR).

 

As has already been said, you are just reusing the same named queue, so there won't really be a leak until you try to shutdown (reference left open).  But the simple solution is to add to your shutdown code to get a reference to the Semaphore and then close with "Force Destroy" set to TRUE.


He's using the same named queue, but he's getting new *references*. He won't create new queues, but he WILL create new *references* to that queue unless I'm totally mixed up on how this works. I think that means there will be a leak since the reference is left open. Am I mistaken believing that?

0 Kudos
Message 5 of 9
(3,034 Views)

@BertMcMahan wrote:

He's using the same named queue, but he's getting new *references*. He won't create new queues, but he WILL create new *references* to that queue unless I'm totally mixed up on how this works. I think that means there will be a leak since the reference is left open. Am I mistaken believing that?


It should be the same reference.  But the queue keeps a count of how many times it was "obtained" and just decrements that count whenever it was "released".  When that count reaches 0 (or the Force Destroy is set to TRUE), the queue itself is actually closed.

 

But I just tried in LabVIEW 2016 and the references are showing to be different (not Equal).  I'll have to find some time to dig around these forums for where this was discussed before.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 6 of 9
(3,006 Views)

Thanks to everybody for the replies.

 

So the consensus is that this will code will indeed lead to a memory leak in two ways - (1) it will leak queue references which I did not close, and (2) the queues will never auto destruct because the ref-counts will never go to zero.

 

I personally find this a little non-intuitive but that's what it is.

 

 

0 Kudos
Message 7 of 9
(2,992 Views)

@crossrulz wrote:


It should be the same reference.  But the queue keeps a count of how many times it was "obtained" and just decrements that count whenever it was "released".  When that count reaches 0 (or the Force Destroy is set to TRUE), the queue itself is actually closed.

 

But I just tried in LabVIEW 2016 and the references are showing to be different (not Equal).  I'll have to find some time to dig around these forums for where this was discussed before.


Why would it be the same reference? Two calls to "Obtain queue" should always return unique references to the same queue, even if it's named. Otherwise, releasing the reference in one spot would kill that same reference for all of the other ones. You *have* to have unique references for each Obtain Queue called, and if you leave the reference wire unconnected, it won't close until the top level VI closes and the autocleanup takes care of the unused reference.

0 Kudos
Message 8 of 9
(2,980 Views)

There are times that I use named queues from different places and I do not want to always make a new one and close the old one in order to prevent memory leaks. I use a construct like below so only one reference is created. At the end of your program you use Force Destroy, or destroy at the end of a process individually.

 

mcduff

 

Snap10.pngSnap11.png

 

0 Kudos
Message 9 of 9
(2,971 Views)