Jump to content

Dynamic Event (Re)Registration


mje

Recommended Posts

I'm curious about a detail of dynamic event registration. Consider the following bit of code (example VI is attached at end of post):

post-11742-0-93171400-1294174491_thumb.p

What's going on in the displayed frame is I'm changing which controls are registered for the mouse enter/leave events based off the value of an enumeration. Works fine, an explicit unregistration for the old array of controls does not appear to be needed.

What I'm wondering about is the atomicity of the registration operation. If A was previously registered, then the code is called so A and B are both registered, is there a set of implicit serial operations where an unregistration is followed by a new registration? That is is there any possibility of missing events from A?

Ignore the fact that these are UI events and the event structure locks the panel until the frame is done (which makes a definite "no" to the question above in this case), I'm wondering more about the general case where I might not be talking about UI events.

-m

dynamic reregistration.vi

Link to comment

What I'm wondering about is the atomicity of the registration operation. If A was previously registered, then the code is called so A and B are both registered, is there a set of implicit serial operations where an unregistration is followed by a new registration? That is is there any possibility of missing events from A?

I don't have a direct answer to your questions, but I did run the vi through the DETT to see if anything interesting popped up. The duration of the Register User Event prim is ~4 us, so if there is a period of time when nothing is registered the event is going to have to be pretty quick to hit that window. :lol:

Link to comment

Heh, that is pretty fast.

I'm just thinking of possible design patterns for something I've been playing with in my mind for a while. If I were to do it event based, at it's heart would be a mechanism similar to the above as objects drop in and out of being subjects. I don't like events that much since I have no control over the underlying queue, but they do have one benefit in that UI events drop right in with zero effort. This is sort of a reverse observer pattern with a single observer, and an unbounded number of subjects. Might be a name for it, but my lack of a formal CS education fails me here in producing a buzzword...

I suspect that since it's a registration refnum, the reference is locked for the duration of the registration primitive, which would force any subject to block when it operates on the reference to queue up an event until after the re-registration is done. But I've learned to not make assumptions like this if they're not documented, especially if you're taking a typical use-case and turning it inside-out.

-m

Link to comment

That is is there any possibility of missing events from A?

When you unregister an event using a null reference, the queue of existing events is flushed. I'm assuming that the same happens with your code, so you would miss any events which occurred and you didn't handle before unregistering. You can fairly easily check this by firing the events, then unregistering.

In any case, I don't understand where you're going with this. The reg refnum and the event refnum are two completely separate objects and they shouldn't affect each other - one is used mainly to fire the event and the other to hold a list of events an event structure currently listens to, so I don't see what kind of syncing you want to get between the two. Perhaps a more realistic example would demo it better.

Link to comment

When you unregister an event using a null reference, the queue of existing events is flushed. I'm assuming that the same happens with your code, so you would miss any events which occurred and you didn't handle before unregistering. You can fairly easily check this by firing the events, then unregistering.

Yes, unregistering does flush the queue. You bring up a very good point though that I never considered, does the queue for A indeed get flushed if it was registered before the call or is it preserved if A is still a subject? I'll write a test case for that, eventually...

In any case, I don't understand where you're going with this. The reg refnum and the event refnum are two completely separate objects and they shouldn't affect each other - one is used mainly to fire the event and the other to hold a list of events an event structure currently listens to, so I don't see what kind of syncing you want to get between the two. Perhaps a more realistic example would demo it better.

Yes, they are distinct objects, however they are both involved when an event signal is generated. I'm under the impression it is the event refnum itself that keeps track of which registration refnums are subscribed to the event, in which case signaling an event must operate on any registrations for that event so the signal can be queued in each registration queue. That's my fundamental understanding of events-- in any language.

The example I posted was trying to boil it down to a simple one-VI example to illustrate what I'm doing. Now that you've brought up the point of flusing, I suppose my general concern is I don't know exactly what's happening in the registration primitive.

If A is already a subject before the registration call and the call is made such that it is again a subject:

  1. Is the existing event queue for A preserved? Easily tested.
  2. Is the registration process atomic? If an event is generated elsewhere which the registration observes during the call to the registration primitive, does the event generation block until the registration is complete? That is is there a possibility of missing event signals? Again, the only case where this matters is when an event is a subject of registration before and after the call.

If the answer to the first question proves to be the queue is flushed, then this whole idea is not implementable using LabVIEW events. I'll have to check this as soon as I can, but if it proves to be preserved, the second question (which is my original one) still remains unanswered and I can't think of a test-case to evaluate as much.

Link to comment

Ok Yair, you had me worried so I whipped this one up:

post-11742-0-43042500-1294243716_thumb.p

The snipped returns an array {1, 2, 3, 4}, which is what I would expect. The registration queue appears to be preserved.

So really, it's my question #2 which stands.

Link to comment

[Edit - Ah, the curse of being a slow writer...]

I'm just thinking of possible design patterns for something I've been playing with in my mind for a while. If I were to do it event based, at it's heart would be a mechanism similar to the above as objects drop in and out of being subjects. I don't like events that much since I have no control over the underlying queue, but they do have one benefit in that UI events drop right in with zero effort. This is sort of a reverse observer pattern with a single observer, and an unbounded number of subjects. Might be a name for it, but my lack of a formal CS education fails me here in producing a buzzword...

I see where you're going with this. I've written a few components that use user events as the primary means of communication to other components. I decided using user events like that is usually more trouble than they're worth. Still, the exercise is worthwhile and I'll be interested in your thoughts on the matter.

A couple things to think about...

-Are the subjects going to have multiple observers? Multiple observers is the primary use case for user events (though that still has issues that need to be carefully considered.) If the subjects only have a single observer the main benefit of user events is unused.

-Who creates and owns the events, the subject or the observer? If the observer creates the event and passes it to the subject, then (in the case of multiple observers) the subject has to maintain a list of event refnums from all the observers. What happens if an observer closes down without notifying the subject? If the subject creates the event and makes the refnum available to the observers, what happens when one of the observers closes the refnum?

-Your comments imply the subjects are interacting directly with the user interface. What happens when you want to reuse one of the subjects in a non-UI component? What is that code going to look like? You'll need one loop with an event structure to handle messages from that subject and another loop to handle the queue-based messages from other threads in the component.

These aren't insurmountable obstacles; just a few things to consider if you're creating an event-based architecture. Like I said, I found it to be more trouble than it's worth. YMMV. Now all my communication between components is done strictly via queues. The one place I do use user events is on the block diagram of UI components, and that's strictly for allowing the mediator loop to send messages to the event handling loop.

I suspect that since it's a registration refnum, the reference is locked for the duration of the registration primitive, which would force any subject to block when it operates on the reference to queue up an event until after the re-registration is done.

Yeah, you'd hope that's the case. Labview R&D guys are smart, so I expect they've anticipated this potential problem. Still, without knowing the details of how the Register For Events and Generate User Event prims work together we can't know an event won't be missed.

If I were to put on my speculator's hat (I love this hat) here's my guess as to how it's implemented with respect to user events. (This model doesn't fully explain all the design-time or run-time behavior, so I know it's not complete. And please 'scuse the inconsistent pseudocode. Structs don't have methods associated with them...)

struct EventRegistrationRefnum {

ptr eventStructure // not visible to Labview users

ptr userEventRefnum [ ]

}

struct UserEventRefnum {

ptr eventStructure [ ] // not visible to Labview users

var userEventData

}

When the Reg Events prim is called it compares the input UsrEv refnums to it's list of currently registered UsrEv refnums. If an input refnum is already registered, there's no need to register it again. If it's not registered, then it calls UserEventRefnum.Register() and passes the UsrEv refnum a reference to the event structure. When the Generate User Event prim is called, it iterates through the list of event structures invoking EventStructure.RaiseEvent() on each one. When the Reg Events prim is finished iterating through the inputs, it checks it's current list of user events and calls UserEventRefnum.Unregister() on those that *weren't* present on the input.

Then again, maybe I'm way off. *shrug* I'm really interested in what a blue says about this.

In any case, I don't understand where you're going with this.

The question is whether calling Reg Events does a hidden unregistration of all the events before re-regestering the events on the inputs. And if it does, what protection is there to prevent an event from being lost in that time between the hidden unregistration and the re-registration.

I've attached a modified example using user events instead of fp events. The question is, when switching from "A only" to "A and B" is there a chance of missing the ToggleA user event?

post-7603-0-69335400-1294252338_thumb.pn

dynamic_reregistration_user_events.vi

Link to comment

I don't really like playing with event references like that, because they have unpredictable behavior under these circumstances.

For example, I modified your example by adding this event and case structure before the loop:

post-1431-0-92330500-1294253291_thumb.pn

If the event structure executes (case T), the array is empty. If it doesn't (case F), it's full. Can you explain why?

You're welcome to have a look here for more details (including from the horse's mouth) about the relation between reg refs and structures, but I don't pretend to safely understand all the intricacies, but that's possibly because I never had a need for such an architecture. I'll leave you guys alone to hash it out.

  • Like 1
Link to comment

If the event structure executes (case T), the array is empty. If it doesn't (case F), it's full. Can you explain why?

You're welcome to have a look here for more details

Thanks for the link Yair. I wasn't aware the event structure flushed the queue and disposed all the events it doesn't specifically handle.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.