LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Notifier reference goes missing when stopping actor in ppl

Solved!
Go to solution

I am trying to write an actor-framework based program using ppls for plugins. I have a core actor which launches various other (nested) actors in ppls.

 

During program shutdown, one of the nested actors needs to close a connection to a USB device. I decided to: create a notifier, send this in the shutdown request to the nested actor, and wait for the nested actor to complete its shutdown operation. The notifier is stored in the nested actor's class data, and a notification is sent when the nested actor's "stop core" method is called. The idea was that once the nested actor has completed its shutdown ok, the core actor can shutdown.

 

When running the application, the core hangs until the "wait on notification" times out. From debugging I find that the notifier refnum seems to go invalid between the "receive message" method and the "handle error" method. I found this out by doing "flatten to string" operations in override methods for "receive message", "handle error", and "stop core". When flattened to string, the value in the class data in the "handle error" method is 0000 0000 when shown in hex. At the exit of the "receive message" method the string is something else (eg 7C10 0000), indicating a real notifier reference.

 

I tried replicating the problem without using ppls. I don't get the issue. There is no timeout, and the notifier is returned properly.

 

What could be causing the refnum to go invalid in the class data between "receive message" and "handle error"? When you look at the actor core, "handle error" immediately follows "receive message", so nothing in the middle should modify the data. Could this be some quirk of ppls? I tried rebuilding all my ppls, but it didn't help.

 

I also have a message enqueuer in the class data, and I note that this is unchanged between "receive message" and "handle error". Could the notifier issue be some reference-tidying? My program decided that the reference was no longer needed and deleted it?

 

I have to do some simplification to upload a simple working example, but the attached image shows the flattened string of the notifier is valid on the input and output of the "receive message" method, but is invalid by the time "stop core" is reached.

0 Kudos
Message 1 of 7
(693 Views)

It could be this. I'm not sure, as your description is lengthy (which isn't bad).

 

Any reference goes invalid when the top level VI of the caller that created it stops running. A VI that is dynamically started is top level of it's hierarchy (not the VI that started the VI dynamically).

 

So once the actor stops, the reference stops existing.

0 Kudos
Message 2 of 7
(668 Views)

Thanks, it is a good thought. I had an issue like that in another application recently. But in this case the VI that created the notification reference is also then waiting for the notification:

 

wwhitley_0-1707930390126.png

 

So the notification reference should not go invalid (at least for the timeout period, which is 5 seconds), since the caller VI is still running, waiting on the notification.

0 Kudos
Message 3 of 7
(651 Views)

While this doesn't directly solve your problem as asked, I would like to ask why you're using a Notifier specifically in this case.

 

Notifiers can be used for something like that but it's not really what they are meant for.  Their design is more oriented towards a "one to many, asynchronous" model, since you can have one central source "broadcasting" notifier updates, and any number of listeners who can get them.  The listeners can either get the most recent notification immediately or specifically wait for a new one to come in, and might miss the occasional notification if they come close together.  It's the sort of thing you might do if you have one process continually taking measurements (from a multimeter or something) and multiple other processes that want to do something with those measurements (such as a display loop, a logging loop, a database loop, etc.).

 

But this sounds like you have one and only one location in your code that needs to receive the notification, and you only need to get notified one time, and you wouldn't want to miss that notification.  This sounds to me a lot more like something you would use a queue for, as they are designed with just one listener and to never miss a message since it'll stay in the queue until you ask for it.

 

I did some experimentation with PPLs and asynchronous VIs and such a while back and I found that named queues seemed to be the messaging system with the least amount of problems crossing the "PPL border" and working with different VI execution hierarchies. If you pass the string containing the name instead of the actual reference, then as long as you don't run "Release Queue" with the "force destroy?" option set anywhere except the message receiver, it doesn't stop working (at least, it never did in my testing). 

 

Is there any reason you can't switch to a one-time use named queue for this?

Message 4 of 7
(631 Views)
Solution
Accepted by wwhitley

Although not the exact same setup, we do something very similar in an Actor based PPL application.

 

We have a specific message "Stop Request.vi" that is used to query from each actor whether they can be stopped, so it uses a Queue to get the response. The only differences I can make out with yours and mine is the Notifier vs Queue, and we include the Queue in the message class itself, instead of doing a double send like yours.
Send vi:

ShockHouse_0-1707938502535.png

Do.vi

ShockHouse_1-1707938522747.png

Drop Message Core:

ShockHouse_2-1707938541690.png

 

 

 

0 Kudos
Message 5 of 7
(603 Views)

Thanks for the suggestions to use a queue instead of notifier. I have something working now using named queues.

 

I realise now there is some bug in my program that means that the class data is being reset to default before the "stop core" method is reached. That's why the notifier was not working, and it stops a queue working if I try to pass the queue or the queue name to "stop core". If I store the queue name in the actor data, it gets reset to a blank string by the time "stop core" is reached, and then the queue cannot be accessed properly.

 

ShockHouse, your strategy of enqueueing in the Do.vi method would avoid the issues I have, since the queue reference is not stored in the actor data. Otherwise I can use a hard-coded queue name in the "stop core" method to avoid needing to pass along the queue name.

 

I think I must have some bug in my compiled ppl causing the actor data to reset to default before "stop core" is reached. All I can think is that I need to build the actor up again from scratch to work out where this bug got introduced.

0 Kudos
Message 6 of 7
(599 Views)

In 25 years of LabVIEW programming, I never used a notifier. I tried them a few times, but they are just too unintuitive (to me) to get to understand them on a usable level.

 

I wouldn't use a 'naked' queue either. By wrapping it in a class you have an easy way to find the functions (where a search for the "Enqueue" function returns all Enqueues). Maybe that sounds like a useless effort (it might be for applications that stay small), but if you use a lot of queues (I don't) it will pay off. And you can change the implementation as long as you don't change the class's contract. So you can easily change the queue of a notifier, private global, DVR or whatever. Just a though...

Message 7 of 7
(551 Views)