08-07-2023
06:04 PM
- last edited on
08-10-2023
10:48 AM
by
NI_Community_Su
The following diagram illustrates an interesting behavioral detail of User Events:
(note that there is a single event structure in this VI... both frames of the event structure are shown in the screenshot)
Outside the loop, two user events are created ('a' and 'b'), and both are immediately fired. There is a 1 second delay, then both user events are destroyed.
Inside the loop, event 'a' fires. There is a 2 second delay, then event 'b' fires, which stops the loop.
But hold on... both user event references are destroyed after the 1 second delay. How could event 'b' fire after its user event reference is destroyed?
It turns out that with events specifically, if you destroy the event reference, an event structure frame for that event will still fire if the event is already in the event queue. This makes events unique among other APIs (queue, notifier, etc.). For example, if you have a queue with elements in it, and you destroy the queue reference, you cannot then dequeue elements that were still in that queue.
In my opinion this behavior makes event programming more straightforward than other APIs... if you fire an event, you're guaranteed that any event structure registered for that event will eventually process it, regardless of what ends up happening to the user event reference for that event.
08-07-2023 06:16 PM
@Darren wrote:
The following diagram illustrates an interesting behavioral detail of User Events:
(note that there is a single event structure in this VI... both frames of the event structure are shown in the screenshot)
Outside the loop, two user events are created ('a' and 'b'), and both are immediately fired. There is a 1 second delay, then both user events are destroyed.
Inside the loop, event 'a' fires. There is a 2 second delay, then event 'b' fires, which stops the loop.
But hold on... both user event references are destroyed after the 1 second delay. How could event 'b' fire after its user event reference is destroyed?
It turns out that with events specifically, if you destroy the event reference, an event structure frame for that event will still fire if the event is already in the event queue. This makes events unique among other APIs (queue, notifier, etc.). For example, if you have a queue with elements in it, and you destroy the queue reference, you cannot then dequeue elements that were still in that queue.
In my opinion this behavior makes event programming more straightforward than other APIs... if you fire an event, you're guaranteed that any event structure registered for that event will eventually process it, regardless of what ends up happening to the user event reference for that event.
Interesting. I've never destroyed user event references until right before the application shuts down because I was paranoid that doing it too early would do exactly what you said wouldn't happen.
08-07-2023 06:27 PM
To further it: unlike Queues, Notifiers, etc. the trick here is that there are two components to each event. There's the user event itself which is the writer and then event registrations are each a queue that feeds the event structure. Writing to a user event uses the Generate User Event to push the data into all attached event registration queues and then the user event has no further interaction with the data being handled from the event registration; the data is already managed by the event registration receiver.
08-07-2023 07:31 PM
Excellent point, Derrick. Thanks for bringing it up.
Another point I wanted to add is that this behavior of Events can be useful during shutdown/cleanup activities. Fire off the events that pertain to shutdown (stop acquisition, disconnect devices, etc.), then destroy the events. You don't need to worry about any sort of timing, waiting for acknowledge, worrying about reference lifetimes, etc... as long as you generated the user events before you destroyed the user events.
08-07-2023 08:04 PM - edited 08-07-2023 08:05 PM
Good point. As Derrick notes, destroying the event does not touch the receiver created when you register for the event. That it’s the registration node, and not the event structure responsible for creating the receiver queue can be demonstrated by inserting a long delay between registration and the while loop.
Btw, there’s racing in your snippet. The events may fire before the registration is performed, in which case your demo will fail 😉
08-07-2023 09:17 PM
@SteenSchmidt wrote:
Btw, there’s racing in your snippet. The events may fire before the registration is performed, in which case your demo will fail 😉
Thanks for pointing that out. Thankfully the point I'm trying to make doesn't depend on that race condition. 😉
08-07-2023 09:21 PM
Great information! IDNKT!
So, for completeness is that behavior prohibiting us from having User Filter Events? Or, is the use case for them not really worth the R&D?
08-07-2023 09:25 PM
@JÞB wrote:
So, for completeness is that behavior prohibiting us from having User Filter Events? Or, is the use case for them not really worth the R&D?
No idea, until reading your reply I didn't know anybody wanted User Filter Events. 😉
08-07-2023 11:35 PM - edited 08-07-2023 11:50 PM
@Darren wrote:
@JÞB wrote:
So, for completeness is that behavior prohibiting us from having User Filter Events? Or, is the use case for them not really worth the R&D?
No idea, until reading your reply I didn't know anybody wanted User Filter Events. 😉
In 25+ years programming in LabVIEW I've wished for User Filter Events a few times. I never ran into a situation where I couldn't find alternatives. Though, at least twice I thought they would be more elegant.
In both of those cases, as I recall, I was modifying inherited code. I'm not sure if User Filter Events would be as useful of a feature for initial development. You could probably persuade me to continue swearing at the original author.
But, y'all down Austin way forget about us poor traveling folk out in the untamed wilderness unless we chime up now and then.
08-08-2023 12:49 AM
Filter user event? Like having a case structure around the logic that stops something from happening in the event case and "discarding" the intended action?