LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Obtain Notifer

I am looking for feedback on a pattern I am considering for named notifiers in a large LabVIEW application.

 

I recently tracked down what appears to be a long-runtime memory/resource problem caused by calling Obtain Notifier inside a loop. In my case, the Obtain Notifier call was not obvious on the top-level diagram. It was buried several layers down in subVIs, and one of those subVIs was being called repeatedly by a long-running loop. 

 

The NI documentation for Obtain Notifier specifically warns about this pattern. For a named notifier, LabVIEW does not simply hand back the exact same reference each time. It returns a new reference to the existing named notifier. If this is done inside a loop, LabVIEW creates a new reference each iteration. NI notes that each new reference consumes additional memory, and in a tight or long-running loop this can look like a memory leak because memory use continues to grow until the VI stops running.  I eventually got 'out of memory error' despite having tons of free RAM.

 

NI documentation page:
https://www.ni.com/docs/en-US/bundle/labview-api-ref/page/functions/obtain-notifier.html

also

https://forums.ni.com/t5/LabVIEW/Re-obtaining-Notifiers-to-Send-Notification-rather-than-wiring/m-p/...

 

The documentation also says Obtain Notifier can return Error 2. I do not know that there is a single fixed “maximum number of notifier handles” that applies in all cases.  If so, I'm curious to what the magic number actually is.

 

My proposed fix is to stop calling Obtain Notifier directly in code. Instead, I am considering wrapping it in a small per-call-site cache VI.

 

The idea is:

  • Configure the helper VI as inline/reentrant so each call site has its own cached reference.
  • Use a feedback node or shift-register style storage.
  • On first call, call Obtain Notifier and cache the returned reference.
  • On later calls from that same call site, return the cached reference.
  • If a prior obtain failed, clear the error and retry obtaining the notifier a limited number of times.
  • Do not call Obtain Notifier on every loop iteration.
  • Do not release/destroy the notifier every iteration.
  • Let final cleanup/shutdown handle releasing references in the proper order.

 

wldgoose_0-1782218884154.png

 

 

 

wldgoose_1-1782218892825.png

 

 

I am thinking this per-call-site cache may be safer than a true global FGV in this application because I cannot always guarantee how the helper will be called across a large codebase. A non-reentrant FGV would create one shared cached reference for the entire application. That may be fine in some designs, but in this case I am more interested in preventing accidental repeated obtains from inside loops while still allowing each call site to own its own cached reference.

 

This may be overkill, especially the retry logic, but my motivation is defensive programming. In a large application, it is easy for a low-level utility VI containing Obtain Notifier to eventually get called from inside a loop without that being obvious at the top level.

 

Yea yea, I know that notifers are basically globals and easy to abuse..  but heck, all data is global if you try hard enough!

 

What are your thoughts?  Anyone doing something similar?

 

-josh

0 Kudos
Message 1 of 6
(87 Views)

To answer one of your questions, the magic number is 2^20. For the most part, each by-reference LabVIEW type can have that many references open.

 

https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019KhWSAU&l=en-US

Message 2 of 6
(67 Views)

@Jacobson wrote:

To answer one of your questions, the magic number is 2^20. For the most part, each by-reference LabVIEW type can have that many references open.

 

https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019KhWSAU&l=en-US


 

 

"The number of simultaneously opened references is therefore limited to 1048575 for each type of reference. "

 

 

That seems about right for the loop iteration time and how long it took to get the Error 2.

 

Cool.

Message 3 of 6
(62 Views)

@wldgoose  a écrit :

My proposed fix is to stop calling Obtain Notifier directly in code. Instead, I am considering wrapping it in a small per-call-site cache VI.

 

The idea is:

  • Configure the helper VI as inline/reentrant so each call site has its own cached reference.
  • Use a feedback node or shift-register style storage.
  • On first call, call Obtain Notifier and cache the returned reference.
  • On later calls from that same call site, return the cached reference.

 


Hello,

 

Just a quick though on it : does each call site will have the exact same Notifier Name for all the application lifetime ?

 

If yes: why not executing Obtain Notifier outside the Loop and passing the reference inside the loop.

If not: then you will have a problem, your subVI may return the reference of another Notifier (the first call will be kept even if the Notifier Name has changed).

0 Kudos
Message 4 of 6
(55 Views)

There are several ways to avoid it. Send the Notifier to the subvi's, do one named Obtain outide the loop and reuse the reference inside the loop, or as you did, use a FGV.

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 5 of 6
(53 Views)

@PinguX wrote:

@wldgoose  a écrit :

My proposed fix is to stop calling Obtain Notifier directly in code. Instead, I am considering wrapping it in a small per-call-site cache VI.

 

The idea is:

  • Configure the helper VI as inline/reentrant so each call site has its own cached reference.
  • Use a feedback node or shift-register style storage.
  • On first call, call Obtain Notifier and cache the returned reference.
  • On later calls from that same call site, return the cached reference.

 


Hello,

 

Just a quick though on it : does each call site will have the exact same Notifier Name for all the application lifetime ?

 

If yes: why not executing Obtain Notifier outside the Loop and passing the reference inside the loop.

If not: then you will have a problem, your subVI may return the reference of another Notifier (the first call will be kept even if the Notifier Name has changed).


 

I was going to make it generic to take any name for the type boolean..

 

Wouldn't the first call only trigger for each instance of the calling VI, as it's in-line'ed?  I always envisioned in-line as just copy and paste this code into the calling block diagram.  so each instance should have its own first call state?

0 Kudos
Message 6 of 6
(13 Views)