Jump to content

Unexpected Event Structure Non-Timeout Behavior


Recommended Posts

Something finally clicked for me during my CLA Summit presentation last week (thanks, Steen, for triggering my brain!).

Here's the issue:

Any event for which an event structure is registered, but for which it does not have a case,
resets the timeout of that event structure anyway.

To put it another way, imagine you have a custom event that's wired to multiple event structures. However, not every event structure actually handles the event (i.e. they don't all have a case for it). When you fire that event, it will reset the timeout counter for all the event structures, even the ones that don't handle the event. This means it's possible to have an event structure in your code that never times out, and also never executes an event handler, even though it's got a non-zero timeout value.

This feels like a bug to me for the following reasons:

  1. We register for Front Panel events by creating event cases for them, and events that don't have cases don't interrupt the timeout. Why would we not expect User Events to work the same way?
  2. It's virtually impossible to detect when this is happening in your code. In the attached example, the event structure looks like it should be timing out, and in a complicated application it's almost impossible to tell why it's not.

However, at the CLA Summit there was some room for disagreement about this. LAVA, what do you think?

Screencast: http://screencast.com/t/qDIKpn9oQnlD

Snippet:

(note the snippet creation made those crazy non-static property nodes on the stop logic; that's not me :) )

post-2992-0-27153300-1300131894_thumb.pn

Code (LV2009): Event Structure Timeout Bug.vi

  • Like 1
Link to comment

Unintuative = yes, bug = no, should it be the default behavior = yes.

Let me explain: I agree that it's unintuative, but I do not agree that it's a bug. Most people would expect that they'd need to write an explicit case for that event to be handled, but the event structure is *receiving* the event, and that resets the timeout - whether it's handling it or not is irrelevant. Try not to confuse "firing events" with "handling events".

Put simply: you registered for an event, the event occured, the event structured saw it - that resets the timeout, irrespective of whether it does something with the event. It's totally the corrrect behavor - the only argument can be whether it's intuative.

Now, should you be able to register and not handle events from the user interface? That's another question :) The "problem" really is that it's not clear what *registration* means, because we don't have explicit "registration" for normal FP events: we just implicitly register for those by creating cases. I still don't think it's a bug though - just because two types of events (and they really are two types) can be registered in a different way doesn't make either of them wrong.

Link to comment

After the CLA Summit on Monday, I did come up with an interesting idea that uses this approach.

Consider this:

Assume you write Alpha.vi that creates a bunch of refnums. As long as that VI keeps running, those refnums stay valid. Give that VI some way of sharing the refnums that it created with other VIs. Have Alpha.vi dynamically register for events that will be fired by those other VIs.

Have those other VIs go off and do work. They work along, firing events. Alpha is registered for those events but because Alpha has no Event Case for those events, Alpha never wakes up from sleeping. That means you have a VI that keeps the refnums alive without ever taking up CPU space itself. Give Alpha a timeout case. If all the other VIs stop work for some amount of time, then the timeout case fires which closes down the refnums.

There may be issues with this approach, and it may not be intuitive, but if I can quickly come up with a use case like this, it means that someone out in the world may have used this same idea for an actual realworld VI, which would make it hard to mutate away. And it might actually be a useful approach -- I'm not sure... someone might want to try it -- which would really enshrine its behavior. :-)

CAR 288741 has been created by Norm Kirchner to track this issue. I added the URL of this discussion thread to the CAR.

Link to comment
There may be issues with this approach, and it may not be intuitive, but if I can quickly come up with a use case like this, it means that someone out in the world may have used this same idea for an actual realworld VI, which would make it hard to mutate away.

It think it could be incredibly useful, especially in cloud computing. We have a reuse architecture that uses something very similar, and are in discussions on how we could use this newly discovered functionality (yes, that's what I'm calling it) to simplify part of that architecture. I don't know why you'd remove this feature of user events because its behavior is inconsistant with FP events - they're two different kettles of fish that just happen to be handled by the same structure IMHO.

We register for Front Panel events by creating event cases for them, and events that don't have cases don't interrupt the timeout. Why would we not expect User Events to work the same way?

I don't think so - user events and FP events aren't the same thing, so neither of them should be limited by the capabilities of the other.

It's virtually impossible to detect when this is happening in your code. In the attached example, the event structure looks like it should be timing out, and in a complicated application it's almost impossible to tell why it's not.

Then you should either lower the complexity of your code, or document it better. That iIt might be difficult to work with in complex code isn't a reason to limit functionality IMO - imagine what other LabVIEW features would be removed if we reviewed everything against this standard.

I agree it would be clearer if LabVIEW were adding one case per dynamic event to the event structure when the register event node is wired to the structure.

Perhaps LabVIEW should note it as a warning (you're registered for an event that you don't handle), because we all have warning reporting turned on, right? :D

Link to comment

*puts his fake CLA hat on*

I'm going to have to jump on the "working as intended" bandwagon. Very neat though, I never considered that you could code something like that.

This is the exact behavior I'd expect given how event registrations and event structures are implemented in LabVIEW. Chris implied as much already, but the event registration is receiving the event, regardless of whether or not there's an event structure around to handle it. It is these very constructs that allow you to register and receive events long before you've blocked on the code which handles the events. I use this construct all the time when calling asynchronous code, without which proper handshaking would be much more cumbersome.

Perhaps LabVIEW should note it as a warning (you're registered for an event that you don't handle), because we all have warning reporting turned on, right?

I think the question is should LabVIEW allow you to code Justin's VI at all? Or should it produce an error? Essentially you you have a structure that doesn't handle all possible cases. Since the event registration refnum is a strict type, all events are known at design time: the event structure should be capable of recognizing the missing event frame. This is analogous to wiring up an enumeration to a case structure, where a value is not handled.

I can see it both ways and I don't think either is "correct". If the event structure were to produce an error, this would enforce consistency with the event registration refnum, and in my opinion be consistent with other LabVIEW structures. I already described the case structure analogy, but also consider event frames which have no source. Delete a registration for a user event for which there was an existing frame, and an error is produced. Why doesn't the opposite hold true (a registration without a frame)?

I do like AQ's use case though. Very interesting.

Time to take the fake hat off and eagerly watch the discussion...

-michael

Link to comment

Great thread, I had no idea and I have to say I don't like to behavior.

all events are known at design time: the event structure should be capable of recognizing the missing event frame. This is analogous to wiring up an enumeration to a case structure, where a value is not handled.

I disagree and I wouldn't want this enforced because of one of my current use cases.

I like to create modules where I can query the list of event refnums (as a cluster).

I then wire this cluster to the Register For Events node. From that point on it is up to me (the developer) to select which events I want to react to at design time for that Event Structure.

The reason I do this is I find this way very simple for what I want to do.

I also like to use the Timeout for how I thought it was intended :P

...it means that someone out in the world may have used this same idea for an actual realworld VI, which would make it hard to mutate away...

Given the above and that there are use cases on both sides, maybe it would be worthwhile to have two Timeout cases:

  • Timeout - the current one where the behavior is to reset on any event received
  • Timeout (Handled Events) - a new one where the behavior is to reset only on receiving any currently handled event

So, rather than a bug, maybe a gap in functionality has been identified?

Link to comment

I disagree and I wouldn't want this enforced because of one of my current use cases.

Just to clarify, I wasn't saying it should produce an error, but rather asking if one should be produced. I see both sides as valid, however if anything I'd say it should stay the way it is for no other reason than precedence has already been set.

Link to comment
This is analogous to wiring up an enumeration to a case structure, where a value is not handled.

Hmmm. I understand your analogy, but I don't think it's completely appropriate in this case (pun intended). It would be true if the event structure was analogous to a case structure, but it's not - it's an event structure, not a case structure. For yout analogy to hold true, we would only be able to have user events, and not FP events.

...I'd say it should stay the way it is for no other reason than precedence has already been set.

I don't think one case really qualifies it as a precedence. (well, less than one, as described above).

Link to comment

I'm in on the Justin and JG bandwagon.thumbup1.gif (not very crowded yet :) )

Doesn't anyone else think that a "timeout" that can never time out is in the least bit strange in concept?blink.gif

Sure you can find a use case for it. But I bet there is far more instances of head-scratching and cries of WTF. On the shoot yourself in the foot scale of 1-10. It's a bit of an 11. It's also one of those "issues" that you come across from time to time where the whole app just doesn't work, but when you try to debug. Everything works fine in isolation (or if you slow it down).

Edited by ShaunR
  • Like 1
Link to comment
Sure you can find a use case for it. But I bet there is far more instances of head-scratching and cries of WTF. On the shoot yourself in the foot scale of 1-10. It's a bit of an 11. It's also one of those "issues" that you come across from time to time where the whole app just doesn't work, but when you try to debug. Everything works fine in isolation (or if you slow it down).

Oh, I'm not saying that it's counterintuative - it totally is, until you stop and thinking about what's going on. That can be said for several things in LabVIEW (remember the first time you branched a by-reference wire and couldn't fathom why the data "on" the other wire was changing?)

Maybe there should be an option to unset this should be available (like an "allow unhandled events to be registered" checkbox in the event dialog if the dynamic event handles are shown). That said, I'm sure AQ will agree that it's a little more complicated than just adding a chekcbox :)

  • Like 1
Link to comment

Maybe there should be an option to unset this should be available (like an "allow unhandled events to be registered" checkbox in the event dialog if the dynamic event handles are shown). That said, I'm sure AQ will agree that it's a little more complicated than just adding a chekcbox :)

Now that is a good idea!

Link to comment

Sure you can find a use case for it. But I bet there is far more instances of head-scratching and cries of WTF. On the shoot yourself in the foot scale of 1-10. It's a bit of an 11. It's also one of those "issues" that you come across from time to time where the whole app just doesn't work, but when you try to debug. Everything works fine in isolation (or if you slow it down).

I guess the good news from this is (for me) - if its taken this long for this issue to be identified (LabVIEW 6.1 to present) then it must not have cropped up much (if not at all) before (granted, we could be using the event structure differently now).

Link to comment

Oh, I'm not saying that it's counterintuative - it totally is, until you stop and thinking about what's going on. That can be said for several things in LabVIEW (remember the first time you branched a by-reference wire and couldn't fathom why the data "on" the other wire was changing?)

Maybe there should be an option to unset this should be available (like an "allow unhandled events to be registered" checkbox in the event dialog if the dynamic event handles are shown). That said, I'm sure AQ will agree that it's a little more complicated than just adding a chekcbox :)

I would actually categorise it as "unexpected behaviour". If it is a bug or not then depends on whether it was specifically designed to not timeout under certain circumstances. My guess is it wasn't considered and "most" developers would want a time-out to, well, time-out rolleyes.gif

I guess the good news from this is (for me) - if its taken this long for this issue to be identified (LabVIEW 6.1 to present) then it must not have cropped up much (if not at all) before (granted, we could be using the event structure differently now).

I think it's probably because most people only use the event case for the UI (and generally wire -1 to it). And only a few are brave enough to base a whole inter-process messaging system purely on events.So if anyone is going to find it....it's you biggrin.gif

Edited by ShaunR
Link to comment
I think it's probably because most people only use the event case for the UI (and generally wire -1 to it). And only a few are brave enough to base a whole inter-process messaging system purely on events.

Hey - if it works, it works rolleyes.gif

..lol

Link to comment

I think it's probably because most people only use the event case for the UI (and generally wire -1 to it).

I would think twice before generalizing like that. User events are at the top of my list and many others I've talked to, when it comes to inter-process communication. Also, using the timeout frame is a common use-case for reading other data that needs polling or other updates between events. In fact, at the CLA summit, there were many requests by other CLAs to extend the capabilities of the Event Structure even further, since handling user events is simply not enough.

Even though, at the end of the day, I'd really like NI to find a solution to this problem which allows me to register for events all willy nilly-like and only selectively create cases to handle them - my gut tells me that, If I I don't need to react on an event then I shouldn't really be registering for it in the first place, should I. For now, I would chalk it up to: "Hey, I just learned something cool and I really should spread the word about this 'best practice' to my colleagues and warn them about it." Education is important.

Maybe there should be an option to unset this should be available (like an "allow unhandled events to be registered" checkbox in the event dialog if the dynamic event handles are shown)

I really like the option of having a right-click menu toggle in the future that would allow you to enforce that you must have a case for every registered event. The default behavior should be as it is now. This way, anyone relying on the old behavior doesn't get screwed during an upgrade. However, I would also like an options switch to allow setting the default mode for event structures. Similar to the auto-grow option. At least, this way there would be a documentation entry which the user can browse to find out more.

Link to comment

I would think twice before generalizing like that.

I think ShaunR is just shy too admit thats how he likes to program too tongue.gif

I really like the option of having a right-click menu toggle in the future that would allow you to enforce that you must have a case for every registered event. The default behavior should be as it is now. This way, anyone relying on the old behavior doesn't get screwed during an upgrade. However, I would also like an options switch to allow setting the default mode for event structures. Similar to the auto-grow option. At least, this way there would be a documentation entry which the user can browse to find out more

I have no idea what new use-cases may be, as this is all news to me as of today but the only issue I can see with the above is that, that option is now mutually exclusive. What if you wanted to react to both pieces of information in the same event structure (there has already been posts above on how users are considering using this new knowledge in their architectures)? You would be limited to one or the other.

Additionally, I use the timeout for polling stuff too, but sometimes I would rather a regular execution regardless of current event activity. I have always thought it would be nice if you could configure the Event Structure to fire off an event every x milliseconds without much programming. Configuring a timer (or multiple timers) would sure be nice.

Link to comment

I would think twice before generalizing like that. User events are at the top of my list and many others I've talked to, when it comes to inter-process communication.

Probably is if you are talking to architects and experienced clds. But "most" labview programmers aren't and the limit of IPC conversations tends to go as far as a producer consumer loop with queues and that's about it.. I've yet to see a student, electrical or electronics engineer (LabVIEW is still seen as a secondary skill in many companies eyes) talk about IPC and messaging systems. And I've worked, and interviewed many.

Also, using the timeout frame is a common use-case for reading other data that needs polling or other updates between events.

And those are exactly the apps that can fall fowl of this "feature".

In fact, at the CLA summit, there were many requests by other CLAs to extend the capabilities of the Event Structure even further, since handling user events is simply not enough.

I've commented many times about how I feel that events have been neglected. So you are preaching to he the converted here.

Even though, at the end of the day, I'd really like NI to find a solution to this problem which allows me to register for events all willy nilly-like and only selectively create cases to handle them - my gut tells me that, If I I don't need to react on an event then I shouldn't really be registering for it in the first place, should I. For now, I would chalk it up to: "Hey, I just learned something cool and I really should spread the word about this 'best practice' to my colleagues and warn them about it." Education is important.

Well. Actually, in the strictest sense, Events shouldn't have a timeout at all. An event is either signalled or is not not. No other language I know of has event time-outs and if a programmer wants to time-out if no event is received within a time-frame, then he has to create a timer that gets reset when an event fires. This is probably why the event case is as it is. The windows forms message callback (Wndproc) just has a timer that gets kicked on entry.

As for not registering unless you need to react. that is only applicable at design time. What if you have configurable alarms? You will still need all the cases on the off-chance that a user will want to register it and receive feedback. thats one of the more useful (but rarely seen in LabVIEW) uses for events.

Unfortunately, I don't think it is "cool". At best it's unexpected behaviour and explains (IMO) a lot about problems people have seen with xControls.

  • Like 1
Link to comment

Lots of good discussion. Just my mesely $0.02...

This doesn't look like a bug to me, but as operating as designed. I don't believe is should produce an error, however I can see it producing a warning.

A use case for this that I can think of is a Watchdog Timer, though, honestly, I would add the non-Timeout event case in as well to clarify the code.

Tim

Link to comment

I see a new future for an "Obfuscated LabVIEW" contest! This feature (of course with misleading documentation) could send a code maintainer on a round-robin chase that could last for weeks if not months :rolleyes:

I think I understand the discussion - Here' what I think I'm reading

1) the event is registered (associated with a structure)

2) it is never handled explicitly in that structure

3)The event fires (somewhere)

4)The event case with no explicit handling implicitly handles the event (which resets the timeout timer)

5) as long as that event keeps getting fired faster than the timeout value, the timeout never executes even though it appears the event structure is sleeping and not handling any events

If this is correct, I have to come down on the side of allowing the user to require the event structure to explicitly handle each event (I think that's what crelf proposed, if I'm following all this) just like removing the default value from case structures requires the user to explicitly implement all cases. I have to have a good, well considered reason to include a default case and I would want a good, well considered reason to have an event case that doesn't explicitly handle an event that I register for.

Mark

  • Like 1
Link to comment

my gut tells me that, If I I don't need to react on an event then I shouldn't really be registering for it in the first place, should I. For now, I would chalk it up to: "Hey, I just learned something cool and I really should spread the word about this 'best practice' to my colleagues and warn them about it." Education is important.

Yep, that's where I'm falling on this, too, especially after AQ explained some of the technical underpinnings to me.

I guess my main frustration with this is that I met at least 4 or 5 CLAs just at the Summit (and that doesn't include everyone else at JKI) who have hit this issue at some point during development, gone half-crazy trying to even understand it, and eventually refactored their code around something they've given up trying to figure out. Why does this happen? Because of the lack of tools at our disposal for monitoring or influencing the Event Structure at runtime.

I honestly don't have a strong opinion on whether this is a bug or not (nor have I; mostly I've been bemused by the whole thing :) ). But what I do have a strong position on is that if I could inspect/flush/otherwise manipulate the queue for an Event Structure I and others would've been able to understand, work around, and even exploit this behavior for better software years ago rather than wasting time cursing at LabVIEW.

  • Like 1
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
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.